19f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson/*
29f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Licensed to the Apache Software Foundation (ASF) under one
39f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * or more contributor license agreements. See the NOTICE file
49f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * distributed with this work for additional information
59f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * regarding copyright ownership. The ASF licenses this file
69f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * to you under the Apache License, Version 2.0 (the  "License");
79f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * you may not use this file except in compliance with the License.
89f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * You may obtain a copy of the License at
99f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *     http://www.apache.org/licenses/LICENSE-2.0
119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Unless required by applicable law or agreed to in writing, software
139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * See the License for the specific language governing permissions and
169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * limitations under the License.
179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */
189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson/*
199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * $Id: NamespaceMappings.java 469648 2006-10-31 20:52:27Z minchau $
209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */
219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonpackage org.apache.xml.serializer;
229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport java.util.Enumeration;
249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport java.util.Hashtable;
259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.xml.sax.ContentHandler;
279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.xml.sax.SAXException;
289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson/**
309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * This class keeps track of the currently defined namespaces. Conceptually the
319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * prefix/uri/depth triplets are pushed on a stack pushed on a stack. The depth
329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * indicates the nesting depth of the element for which the mapping was made.
339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <p>For example:
359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <pre>
369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <chapter xmlns:p1="def">
379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *   <paragraph xmlns:p2="ghi">
389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *      <sentance xmlns:p3="jkl">
399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *      </sentance>
409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *    </paragraph>
419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *    <paragraph xlmns:p4="mno">
429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *    </paragraph>
439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * </chapter>
449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * </pre>
459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * When the <chapter> element is encounted the prefix "p1" associated with uri
479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * "def" is pushed on the stack with depth 1.
489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * When the first <paragraph> is encountered "p2" and "ghi" are pushed with
499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * depth 2.
509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * When the <sentance> is encountered "p3" and "jkl" are pushed with depth 3.
519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * When </sentance> occurs the popNamespaces(3) will pop "p3"/"jkl" off the
529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * stack.  Of course popNamespaces(2) would pop anything with depth 2 or
539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * greater.
549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * So prefix/uri pairs are pushed and poped off the stack as elements are
569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * processed.  At any given moment of processing the currently visible prefixes
579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * are on the stack and a prefix can be found given a uri, or a uri can be found
589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * given a prefix.
599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * This class is intended for internal use only.  However, it is made public because
619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * other packages require it.
629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @xsl.usage internal
639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */
649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonpublic class NamespaceMappings
659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson{
669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /**
679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * This member is continually incremented when new prefixes need to be
689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * generated. ("ns0"  "ns1" ...)
699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     */
709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    private int count = 0;
719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /**
739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * Each entry (prefix) in this hashtable points to a Stack of URIs
749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * This table maps a prefix (String) to a Stack of NamespaceNodes.
759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * All Namespace nodes in that retrieved stack have the same prefix,
769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * though possibly different URI's or depths. Such a stack must have
779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * mappings at deeper depths push later on such a stack.  Mappings pushed
789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * earlier on the stack will have smaller values for MappingRecord.m_declarationDepth.
799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     */
809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    private Hashtable m_namespaces = new Hashtable();
819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /**
839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * This stack is used as a convenience.
849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * It contains the pushed NamespaceNodes (shallowest
859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * to deepest) and is used to delete NamespaceNodes
869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * when leaving the current element depth
879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * to returning to the parent. The mappings of the deepest
889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * depth can be popped of the top and the same node
899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * can be removed from the appropriate prefix stack.
909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     *
919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * All prefixes pushed at the current depth can be
929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * removed at the same time by using this stack to
939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * ensure prefix/uri map scopes are closed correctly.
949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     */
959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    private Stack m_nodeStack = new Stack();
969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    private static final String EMPTYSTRING = "";
989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    private static final String XML_PREFIX = "xml"; // was "xmlns"
999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /**
1019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * Default constructor
1029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * @see java.lang.Object#Object()
1039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     */
1049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    public NamespaceMappings()
1059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
1069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        initNamespaces();
1079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
1089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /**
1109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * This method initializes the namespace object with appropriate stacks
1119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * and predefines a few prefix/uri pairs which always exist.
1129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     */
1139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    private void initNamespaces()
1149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
1159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // The initial prefix mappings will never be deleted because they are at element depth -1
1169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // (a kludge)
1179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // Define the default namespace (initially maps to "" uri)
1199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        Stack stack;
1209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        MappingRecord nn;
1219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        nn = new MappingRecord(EMPTYSTRING, EMPTYSTRING, -1);
1229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        stack = createPrefixStack(EMPTYSTRING);
1239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        stack.push(nn);
1249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // define "xml" namespace
1269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        nn = new MappingRecord(XML_PREFIX, "http://www.w3.org/XML/1998/namespace", -1);
1279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        stack = createPrefixStack(XML_PREFIX);
1289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        stack.push(nn);
1299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
1309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /**
1329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * Use a namespace prefix to lookup a namespace URI.
1339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     *
1349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * @param prefix String the prefix of the namespace
1359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * @return the URI corresponding to the prefix, returns ""
1369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * if there is no visible mapping.
1379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     */
1389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    public String lookupNamespace(String prefix)
1399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
1409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        String uri = null;
1419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        final Stack stack = getPrefixStack(prefix);
1429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        if (stack != null && !stack.isEmpty()) {
1439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            uri = ((MappingRecord) stack.peek()).m_uri;
1449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
1459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        if (uri == null)
1469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            uri = EMPTYSTRING;
1479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        return uri;
1489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
1499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    MappingRecord getMappingFromPrefix(String prefix) {
1529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        final Stack stack = (Stack) m_namespaces.get(prefix);
1539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        return stack != null && !stack.isEmpty() ?
1549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            ((MappingRecord) stack.peek()) : null;
1559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
1569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /**
1589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * Given a namespace uri, and the namespaces mappings for the
1599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * current element, return the current prefix for that uri.
1609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     *
1619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * @param uri the namespace URI to be search for
1629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * @return an existing prefix that maps to the given URI, null if no prefix
1639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * maps to the given namespace URI.
1649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     */
1659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    public String lookupPrefix(String uri)
1669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
1679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        String foundPrefix = null;
1689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        Enumeration prefixes = m_namespaces.keys();
1699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        while (prefixes.hasMoreElements())
1709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        {
1719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            String prefix = (String) prefixes.nextElement();
1729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            String uri2 = lookupNamespace(prefix);
1739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            if (uri2 != null && uri2.equals(uri))
1749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            {
1759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                foundPrefix = prefix;
1769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                break;
1779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            }
1789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
1799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        return foundPrefix;
1809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
1819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    MappingRecord getMappingFromURI(String uri)
1839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
1849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        MappingRecord foundMap = null;
1859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        Enumeration prefixes = m_namespaces.keys();
1869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        while (prefixes.hasMoreElements())
1879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        {
1889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            String prefix = (String) prefixes.nextElement();
1899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            MappingRecord map2 = getMappingFromPrefix(prefix);
1909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            if (map2 != null && (map2.m_uri).equals(uri))
1919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            {
1929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                foundMap = map2;
1939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                break;
1949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            }
1959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
1969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        return foundMap;
1979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
1989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /**
2009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * Undeclare the namespace that is currently pointed to by a given prefix
2019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     */
2029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    boolean popNamespace(String prefix)
2039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
2049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // Prefixes "xml" and "xmlns" cannot be redefined
2059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        if (prefix.startsWith(XML_PREFIX))
2069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        {
2079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            return false;
2089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
2099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        Stack stack;
2119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        if ((stack = getPrefixStack(prefix)) != null)
2129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        {
2139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            stack.pop();
2149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            return true;
2159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
2169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        return false;
2179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
2189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /**
2209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * Declare a mapping of a prefix to namespace URI at the given element depth.
2219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * @param prefix a String with the prefix for a qualified name
2229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * @param uri a String with the uri to which the prefix is to map
2239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * @param elemDepth the depth of current declaration
2249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     */
2259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    public boolean pushNamespace(String prefix, String uri, int elemDepth)
2269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
2279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // Prefixes "xml" and "xmlns" cannot be redefined
2289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        if (prefix.startsWith(XML_PREFIX))
2299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        {
2309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            return false;
2319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
2329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        Stack stack;
2349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // Get the stack that contains URIs for the specified prefix
2359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        if ((stack = (Stack) m_namespaces.get(prefix)) == null)
2369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        {
2379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            m_namespaces.put(prefix, stack = new Stack());
2389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
2399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        if (!stack.empty())
2419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        {
2429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            MappingRecord mr = (MappingRecord)stack.peek();
2439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            if (uri.equals(mr.m_uri) || elemDepth == mr.m_declarationDepth) {
2449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                // If the same prefix/uri mapping is already on the stack
2459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                // don't push this one.
2469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                // Or if we have a mapping at the same depth
2479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                // don't replace by pushing this one.
2489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                return false;
2499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            }
2509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
2519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        MappingRecord map = new MappingRecord(prefix,uri,elemDepth);
2529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        stack.push(map);
2539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        m_nodeStack.push(map);
2549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        return true;
2559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
2569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /**
2589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * Pop, or undeclare all namespace definitions that are currently
2599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * declared at the given element depth, or deepter.
2609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * @param elemDepth the element depth for which mappings declared at this
2619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * depth or deeper will no longer be valid
2629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * @param saxHandler The ContentHandler to notify of any endPrefixMapping()
2639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * calls.  This parameter can be null.
2649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     */
2659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    void popNamespaces(int elemDepth, ContentHandler saxHandler)
2669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
2679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        while (true)
2689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        {
2699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            if (m_nodeStack.isEmpty())
2709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                return;
2719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            MappingRecord map = (MappingRecord) (m_nodeStack.peek());
2729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            int depth = map.m_declarationDepth;
2739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            if (elemDepth < 1 || map.m_declarationDepth < elemDepth)
2749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                break;
2759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            /* the depth of the declared mapping is elemDepth or deeper
2769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson             * so get rid of it
2779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson             */
2789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            MappingRecord nm1 = (MappingRecord) m_nodeStack.pop();
2809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            // pop the node from the stack
2819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            String prefix = map.m_prefix;
2829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            Stack prefixStack = getPrefixStack(prefix);
2849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            MappingRecord nm2 = (MappingRecord) prefixStack.peek();
2859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            if (nm1 == nm2)
2869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            {
2879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                // It would be nice to always pop() but we
2889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                // need to check that the prefix stack still has
2899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                // the node we want to get rid of. This is because
2909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                // the optimization of essentially this situation:
2919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                // <a xmlns:x="abc"><b xmlns:x="" xmlns:x="abc" /></a>
2929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                // will remove both mappings in <b> because the
2939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                // new mapping is the same as the masked one and we get
2949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                // <a xmlns:x="abc"><b/></a>
2959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                // So we are only removing xmlns:x="" or
2969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                // xmlns:x="abc" from the depth of element <b>
2979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                // when going back to <a> if in fact they have
2989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                // not been optimized away.
2999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                //
3009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                prefixStack.pop();
3019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                if (saxHandler != null)
3029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                {
3039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                    try
3049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                    {
3059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                        saxHandler.endPrefixMapping(prefix);
3069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                    }
3079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                    catch (SAXException e)
3089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                    {
3099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                        // not much we can do if they aren't willing to listen
3109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                    }
3119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                }
3129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            }
3139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
3159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
3169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /**
3189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * Generate a new namespace prefix ( ns0, ns1 ...) not used before
3199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * @return String a new namespace prefix ( ns0, ns1, ns2 ...)
3209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     */
3219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    public String generateNextPrefix()
3229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
3239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        return "ns" + (count++);
3249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
3259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /**
3289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * This method makes a clone of this object.
3299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     *
3309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     */
3319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    public Object clone() throws CloneNotSupportedException {
3329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        NamespaceMappings clone = new NamespaceMappings();
3339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        clone.m_nodeStack = (NamespaceMappings.Stack) m_nodeStack.clone();
3349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        clone.count = this.count;
3359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        clone.m_namespaces = (Hashtable) m_namespaces.clone();
3369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        clone.count = count;
3389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        return clone;
3399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
3419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    final void reset()
3439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
3449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        this.count = 0;
3459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        this.m_namespaces.clear();
3469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        this.m_nodeStack.clear();
3479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        initNamespaces();
3499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
3509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /**
3529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * Just a little class that ties the 3 fields together
3539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * into one object, and this simplifies the pushing
3549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * and popping of namespaces to one push or one pop on
3559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * one stack rather than on 3 separate stacks.
3569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     */
3579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    class MappingRecord {
3589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        final String m_prefix;  // the prefix
3599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        final String m_uri;     // the uri, possibly "" but never null
3609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // the depth of the element where declartion was made
3619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        final int m_declarationDepth;
3629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        MappingRecord(String prefix, String uri, int depth) {
3639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            m_prefix = prefix;
3649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            m_uri = (uri==null)? EMPTYSTRING : uri;
3659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            m_declarationDepth = depth;
3669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
3679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
3689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /**
3709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * Rather than using java.util.Stack, this private class
3719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * provides a minimal subset of methods and is faster
3729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * because it is not thread-safe.
3739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     */
3749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    private class Stack {
3759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        private int top = -1;
3769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        private int max = 20;
3779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        Object[] m_stack = new Object[max];
3789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        public Object clone() throws CloneNotSupportedException {
3809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            NamespaceMappings.Stack clone = new NamespaceMappings.Stack();
3819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            clone.max = this.max;
3829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            clone.top = this.top;
3839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            clone.m_stack = new Object[clone.max];
3849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            for (int i=0; i <= top; i++) {
3859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            	// We are just copying references to immutable MappingRecord objects here
3869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            	// so it is OK if the clone has references to these.
3879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            	clone.m_stack[i] = this.m_stack[i];
3889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            }
3899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            return clone;
3909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
3919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        public Stack()
3939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        {
3949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
3959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        public Object push(Object o) {
3979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            top++;
3989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            if (max <= top) {
3999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                int newMax = 2*max + 1;
4009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                Object[] newArray = new Object[newMax];
4019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                System.arraycopy(m_stack,0, newArray, 0, max);
4029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                max = newMax;
4039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                m_stack = newArray;
4049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            }
4059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            m_stack[top] = o;
4069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            return o;
4079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
4089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        public Object pop() {
4109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            Object o;
4119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            if (0 <= top) {
4129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                o = m_stack[top];
4139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                // m_stack[top] = null;  do we really care?
4149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                top--;
4159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            }
4169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            else
4179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                o = null;
4189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            return o;
4199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
4209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        public Object peek() {
4229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            Object o;
4239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            if (0 <= top) {
4249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                o = m_stack[top];
4259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            }
4269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            else
4279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                o = null;
4289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            return o;
4299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
4309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        public Object peek(int idx) {
4329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            return m_stack[idx];
4339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
4349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        public boolean isEmpty() {
4369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            return (top < 0);
4379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
4389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        public boolean empty() {
4399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            return (top < 0);
4409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
4419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        public void clear() {
4439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            for (int i=0; i<= top; i++)
4449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                m_stack[i] = null;
4459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            top = -1;
4469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
4479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        public Object getElement(int index) {
4499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            return m_stack[index];
4509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
4519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
4529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /**
4539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * A more type-safe way to get a stack of prefix mappings
4549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * from the Hashtable m_namespaces
4559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * (this is the only method that does the type cast).
4569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     */
4579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    private Stack getPrefixStack(String prefix) {
4599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        Stack fs = (Stack) m_namespaces.get(prefix);
4609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        return fs;
4619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
4629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /**
4649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * A more type-safe way of saving stacks under the
4659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * m_namespaces Hashtable.
4669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     */
4679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    private Stack createPrefixStack(String prefix)
4689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
4699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        Stack fs = new Stack();
4709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        m_namespaces.put(prefix, fs);
4719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        return fs;
4729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
4739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /**
4759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * Given a namespace uri, get all prefixes bound to the Namespace URI in the current scope.
4769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     *
4779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * @param uri the namespace URI to be search for
4789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * @return An array of Strings which are
4799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * all prefixes bound to the namespace URI in the current scope.
4809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * An array of zero elements is returned if no prefixes map to the given
4819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * namespace URI.
4829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     */
4839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    public String[] lookupAllPrefixes(String uri)
4849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
4859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        java.util.ArrayList foundPrefixes = new java.util.ArrayList();
4869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        Enumeration prefixes = m_namespaces.keys();
4879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        while (prefixes.hasMoreElements())
4889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        {
4899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            String prefix = (String) prefixes.nextElement();
4909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            String uri2 = lookupNamespace(prefix);
4919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            if (uri2 != null && uri2.equals(uri))
4929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            {
4939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                foundPrefixes.add(prefix);
4949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            }
4959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
4969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        String[] prefixArray = new String[foundPrefixes.size()];
4979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        foundPrefixes.toArray(prefixArray);
4989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        return prefixArray;
4999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
5009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson}
501