KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xml > serializer > NamespaceMappings


1 /*
2  * Copyright 2003-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 /*
17  * $Id: NamespaceMappings.java,v 1.6 2004/02/17 04:18:18 minchau Exp $
18  */

19 package org.apache.xml.serializer;
20
21 import java.util.Enumeration JavaDoc;
22 import java.util.Hashtable JavaDoc;
23 import java.util.Stack JavaDoc;
24
25 import org.xml.sax.ContentHandler JavaDoc;
26 import org.xml.sax.SAXException JavaDoc;
27
28 /**
29  * This class keeps track of the currently defined namespaces. Conceptually the
30  * prefix/uri/depth triplets are pushed on a stack pushed on a stack. The depth
31  * indicates the nesting depth of the element for which the mapping was made.
32  *
33  * <p>For example:
34  * <pre>
35  * <chapter xmlns:p1="def">
36  * <paragraph xmlns:p2="ghi">
37  * <sentance xmlns:p3="jkl">
38  * </sentance>
39  * </paragraph>
40  * <paragraph xlmns:p4="mno">
41  * </paragraph>
42  * </chapter>
43  * </pre>
44  *
45  * When the <chapter> element is encounted the prefix "p1" associated with uri
46  * "def" is pushed on the stack with depth 1.
47  * When the first <paragraph> is encountered "p2" and "ghi" are pushed with
48  * depth 2.
49  * When the <sentance> is encountered "p3" and "jkl" are pushed with depth 3.
50  * When </sentance> occurs the popNamespaces(3) will pop "p3"/"jkl" off the
51  * stack. Of course popNamespaces(2) would pop anything with depth 2 or
52  * greater.
53  *
54  * So prefix/uri pairs are pushed and poped off the stack as elements are
55  * processed. At any given moment of processing the currently visible prefixes
56  * are on the stack and a prefix can be found given a uri, or a uri can be found
57  * given a prefix.
58  */

59 public class NamespaceMappings
60 {
61     /**
62      * This member is continually incremented when new prefixes need to be
63      * generated. ("ns0" "ns1" ...)
64      */

65     private int count = 0;
66
67     /**
68      * Stack of prefixes that have mappings
69      * The top of this stack is the prefix that was last mapped to an URI
70      *
71      * For every prefix pushed on this stack a corresponding integer is pushed
72      * on the m_nodeStack. That way all prefixes pushed at the current depth can
73      * be removed at the same time.
74      */

75     private java.util.Stack JavaDoc m_prefixStack = new Stack JavaDoc();
76
77     /**
78      * Each entry (prefix) in this hashtable points to a Stack of URIs
79      */

80     private Hashtable JavaDoc m_namespaces = new Hashtable JavaDoc();
81
82     /**
83      * The top of this stack contains the nested element depth
84      * of the last declared a namespace.
85      * Used to know how many prefix mappings to pop when leaving
86      * the current element depth.
87      * For every prefix mapping the current element depth is
88      * pushed on this stack, as well as the prefix on the m_prefixStack
89      * That way all prefixes pushed at the current depth can be
90      * removed at the same time.
91      * Used to ensure prefix/uri map scopes are closed correctly
92      *
93      */

94     private Stack JavaDoc m_nodeStack = new Stack JavaDoc();
95
96     private static final String JavaDoc EMPTYSTRING = "";
97     private static final String JavaDoc XML_PREFIX = "xml"; // was "xmlns"
98

99     /**
100      * Default constructor
101      * @see java.lang.Object#Object()
102      */

103     public NamespaceMappings()
104     {
105         initNamespaces();
106     }
107
108     /**
109      * This method initializes the namespace object with appropriate stacks
110      * and predefines a few prefix/uri pairs which always exist.
111      */

112     private void initNamespaces()
113     {
114  
115
116         // Define the default namespace (initially maps to "" uri)
117
Stack JavaDoc stack;
118         m_namespaces.put(EMPTYSTRING, stack = new Stack JavaDoc());
119         stack.push(EMPTYSTRING);
120         m_prefixStack.push(EMPTYSTRING);
121
122         m_namespaces.put(XML_PREFIX, stack = new Stack JavaDoc());
123         stack.push("http://www.w3.org/XML/1998/namespace");
124         m_prefixStack.push(XML_PREFIX);
125
126         m_nodeStack.push(new Integer JavaDoc(-1));
127
128     }
129
130     /**
131      * Use a namespace prefix to lookup a namespace URI.
132      *
133      * @param prefix String the prefix of the namespace
134      * @return the URI corresponding to the prefix
135      */

136     public String JavaDoc lookupNamespace(String JavaDoc prefix)
137     {
138         final Stack JavaDoc stack = (Stack JavaDoc) m_namespaces.get(prefix);
139         return stack != null && !stack.isEmpty() ? (String JavaDoc) stack.peek() : null;
140     }
141
142     /**
143      * Given a namespace uri, and the namespaces mappings for the
144      * current element, return the current prefix for that uri.
145      *
146      * @param uri the namespace URI to be search for
147      * @return an existing prefix that maps to the given URI, null if no prefix
148      * maps to the given namespace URI.
149      */

150     public String JavaDoc lookupPrefix(String JavaDoc uri)
151     {
152         String JavaDoc foundPrefix = null;
153         Enumeration JavaDoc prefixes = m_namespaces.keys();
154         while (prefixes.hasMoreElements())
155         {
156             String JavaDoc prefix = (String JavaDoc) prefixes.nextElement();
157             String JavaDoc uri2 = lookupNamespace(prefix);
158             if (uri2 != null && uri2.equals(uri))
159             {
160                 foundPrefix = prefix;
161                 break;
162             }
163         }
164         return foundPrefix;
165     }
166
167     /**
168      * Undeclare the namespace that is currently pointed to by a given prefix
169      */

170     public boolean popNamespace(String JavaDoc prefix)
171     {
172         // Prefixes "xml" and "xmlns" cannot be redefined
173
if (prefix.startsWith(XML_PREFIX))
174         {
175             return false;
176         }
177
178         Stack JavaDoc stack;
179         if ((stack = (Stack JavaDoc) m_namespaces.get(prefix)) != null)
180         {
181             stack.pop();
182             return true;
183         }
184         return false;
185     }
186
187     /**
188      * Declare a prefix to point to a namespace URI
189      * @param prefix a String with the prefix for a qualified name
190      * @param uri a String with the uri to which the prefix is to map
191      * @param elemDepth the depth of current declaration
192      */

193     public boolean pushNamespace(String JavaDoc prefix, String JavaDoc uri, int elemDepth)
194     {
195         // Prefixes "xml" and "xmlns" cannot be redefined
196
if (prefix.startsWith(XML_PREFIX))
197         {
198             return false;
199         }
200
201         Stack JavaDoc stack;
202         // Get the stack that contains URIs for the specified prefix
203
if ((stack = (Stack JavaDoc) m_namespaces.get(prefix)) == null)
204         {
205             m_namespaces.put(prefix, stack = new Stack JavaDoc());
206         }
207
208         if (!stack.empty() && uri.equals(stack.peek()))
209         {
210             return false;
211         }
212
213         stack.push(uri);
214         m_prefixStack.push(prefix);
215         m_nodeStack.push(new Integer JavaDoc(elemDepth));
216         return true;
217     }
218
219     /**
220      * Pop, or undeclare all namespace definitions that are currently
221      * declared at the given element depth, or deepter.
222      * @param elemDepth the element depth for which mappings declared at this
223      * depth or deeper will no longer be valid
224      * @param saxHandler The ContentHandler to notify of any endPrefixMapping()
225      * calls. This parameter can be null.
226      */

227     public void popNamespaces(int elemDepth, ContentHandler JavaDoc saxHandler)
228     {
229         while (true)
230         {
231             if (m_nodeStack.isEmpty())
232                 return;
233             Integer JavaDoc i = (Integer JavaDoc) (m_nodeStack.peek());
234             if (i.intValue() < elemDepth)
235                 return;
236             /* the depth of the declared mapping is elemDepth or deeper
237              * so get rid of it
238              */

239
240             m_nodeStack.pop();
241             final String JavaDoc prefix = (String JavaDoc) m_prefixStack.pop();
242             popNamespace(prefix);
243             if (saxHandler != null)
244             {
245                 try
246                 {
247                     saxHandler.endPrefixMapping(prefix);
248                 }
249                 catch (SAXException JavaDoc e)
250                 {
251                     // not much we can do if they aren't willing to listen
252
}
253             }
254                
255         }
256     }
257
258     /**
259      * Generate a new namespace prefix ( ns0, ns1 ...) not used before
260      * @return String a new namespace prefix ( ns0, ns1, ns2 ...)
261      */

262     public String JavaDoc generateNextPrefix()
263     {
264         return "ns" + (count++);
265     }
266
267  
268     /**
269      * This method makes a clone of this object.
270      *
271      */

272     public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc {
273         NamespaceMappings clone = new NamespaceMappings();
274         clone.m_prefixStack = (Stack JavaDoc)m_prefixStack.clone();
275         clone.m_nodeStack = (Stack JavaDoc) m_nodeStack.clone();
276         clone.m_namespaces = (Hashtable JavaDoc) m_namespaces.clone();
277         
278         clone.count = count;
279         return clone;
280         
281     }
282     
283     public final void reset()
284     {
285         this.count = 0;
286         this.m_namespaces.clear();
287         this.m_nodeStack.clear();
288         this.m_prefixStack.clear();
289         
290         initNamespaces();
291     }
292
293 }
294
Popular Tags