Clover coverage report - dom4j - 1.6.1 Coverage timestamp: ma mei 16 2005 14:23:01 GMT+01:00 FRAMES NO FRAMES |
file stats: | LOC: | 504 |  | Methods: | 25
| NCLOC: | 229 |  | Classes: | 1
Source file | Conditionals | Statements | Methods | TOTAL
NamespaceStack.java | 77,9% | 88% | 88% | 84,9% |

1 |  | /*
2 |  | * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
3 |  | *
4 |  | * This software is open source.
5 |  | * See the bottom of this file for the licence.
6 |  | */
7 |  |
8 |  | package org.dom4j.tree;
9 |  |
10 |  | import java.util.ArrayList;
11 |  | import java.util.HashMap;
12 |  | import java.util.Map;
13 |  |
14 |  | import org.dom4j.DocumentFactory;
15 |  | import org.dom4j.Namespace;
16 |  | import org.dom4j.QName;
17 |  |
18 |  | /**
19 |  | * NamespaceStack implements a stack of namespaces and optionally maintains a
20 |  | * cache of all the fully qualified names (<code>QName</code>) which are in
21 |  | * scope. This is useful when building or navigating a <i>dom4j </i> document.
22 |  | *
23 |  | * @author <a href="mailto:jstrachan@apache.org">James Strachan </a>
24 |  | * @version $Revision: 1.13 $
25 |  | */
26 |  | public class NamespaceStack {
27 |  | /** The factory used to create new <code>Namespace</code> instances */
28 |  | private DocumentFactory documentFactory;
29 |  |
30 |  | /** The Stack of namespaces */
31 |  | private ArrayList namespaceStack = new ArrayList();
32 |  |
33 |  | /** The cache of qualifiedNames to QNames per namespace context */
34 |  | private ArrayList namespaceCacheList = new ArrayList();
35 |  |
36 |  | /**
37 |  | * A cache of current namespace context cache of mapping from qualifiedName
38 |  | * to QName
39 |  | */
40 |  | private Map currentNamespaceCache;
41 |  |
42 |  | /**
43 |  | * A cache of mapping from qualifiedName to QName before any namespaces are
44 |  | * declared
45 |  | */
46 |  | private Map rootNamespaceCache = new HashMap();
47 |  |
48 |  | /** Caches the default namespace defined via xmlns="" */
49 |  | private Namespace defaultNamespace;
50 |  |
51 | 2198 | public NamespaceStack() {
52 | 2198 | this.documentFactory = DocumentFactory.getInstance();
53 |  | }
54 |  |
55 | 5831 | public NamespaceStack(DocumentFactory documentFactory) {
56 | 5831 | this.documentFactory = documentFactory;
57 |  | }
58 |  |
59 |  | /**
60 |  | * Pushes the given namespace onto the stack so that its prefix becomes
61 |  | * available.
62 |  | *
63 |  | * @param namespace
64 |  | * is the <code>Namespace</code> to add to the stack.
65 |  | */
66 | 8825 | public void push(Namespace namespace) {
67 | 8825 | namespaceStack.add(namespace);
68 | 8825 | namespaceCacheList.add(null);
69 | 8825 | currentNamespaceCache = null;
70 |  |
71 | 8825 | String prefix = namespace.getPrefix();
72 |  |
73 | 8825 | if ((prefix == null) || (prefix.length() == 0)) {
74 | 2374 | defaultNamespace = namespace;
75 |  | }
76 |  | }
77 |  |
78 |  | /**
79 |  | * Pops the most recently used <code>Namespace</code> from the stack
80 |  | *
81 |  | * @return Namespace popped from the stack
82 |  | */
83 | 744 | public Namespace pop() {
84 | 744 | return remove(namespaceStack.size() - 1);
85 |  | }
86 |  |
87 |  | /**
88 |  | * DOCUMENT ME!
89 |  | *
90 |  | * @return the number of namespaces on the stackce stack.
91 |  | */
92 | 163293 | public int size() {
93 | 163293 | return namespaceStack.size();
94 |  | }
95 |  |
96 |  | /**
97 |  | * Clears the stack
98 |  | */
99 | 11678 | public void clear() {
100 | 11678 | namespaceStack.clear();
101 | 11678 | namespaceCacheList.clear();
102 | 11678 | rootNamespaceCache.clear();
103 | 11678 | currentNamespaceCache = null;
104 |  | }
105 |  |
106 |  | /**
107 |  | * DOCUMENT ME!
108 |  | *
109 |  | * @param index
110 |  | * DOCUMENT ME!
111 |  | *
112 |  | * @return the namespace at the specified index on the stack
113 |  | */
114 | 5884 | public Namespace getNamespace(int index) {
115 | 5884 | return (Namespace) namespaceStack.get(index);
116 |  | }
117 |  |
118 |  | /**
119 |  | * DOCUMENT ME!
120 |  | *
121 |  | * @param prefix
122 |  | * DOCUMENT ME!
123 |  | *
124 |  | * @return the namespace for the given prefix or null if it could not be
125 |  | * found.
126 |  | */
127 | 2140 | public Namespace getNamespaceForPrefix(String prefix) {
128 | 2140 | if (prefix == null) {
129 | 0 | prefix = "";
130 |  | }
131 |  |
132 | 2140 | for (int i = namespaceStack.size() - 1; i >= 0; i--) {
133 | 2767 | Namespace namespace = (Namespace) namespaceStack.get(i);
134 |  |
135 | 2767 | if (prefix.equals(namespace.getPrefix())) {
136 | 1532 | return namespace;
137 |  | }
138 |  | }
139 |  |
140 | 608 | return null;
141 |  | }
142 |  |
143 |  | /**
144 |  | * DOCUMENT ME!
145 |  | *
146 |  | * @param prefix
147 |  | * DOCUMENT ME!
148 |  | *
149 |  | * @return the URI for the given prefix or null if it could not be found.
150 |  | */
151 | 14 | public String getURI(String prefix) {
152 | 14 | Namespace namespace = getNamespaceForPrefix(prefix);
153 |  |
154 | 14 | return (namespace != null) ? namespace.getURI() : null;
155 |  | }
156 |  |
157 |  | /**
158 |  | * DOCUMENT ME!
159 |  | *
160 |  | * @param namespace
161 |  | * DOCUMENT ME!
162 |  | *
163 |  | * @return true if the given prefix is in the stack.
164 |  | */
165 | 20698 | public boolean contains(Namespace namespace) {
166 | 20698 | String prefix = namespace.getPrefix();
167 | 20698 | Namespace current = null;
168 |  |
169 | 20698 | if ((prefix == null) || (prefix.length() == 0)) {
170 | 18575 | current = getDefaultNamespace();
171 |  | } else {
172 | 2123 | current = getNamespaceForPrefix(prefix);
173 |  | }
174 |  |
175 | 20698 | if (current == null) {
176 | 622 | return false;
177 |  | }
178 |  |
179 | 20076 | if (current == namespace) {
180 | 19967 | return true;
181 |  | }
182 |  |
183 | 109 | return namespace.getURI().equals(current.getURI());
184 |  | }
185 |  |
186 | 94617 | public QName getQName(String namespaceURI, String localName,
187 |  | String qualifiedName) {
188 | 94577 | if (localName == null) {
189 | 11 | localName = qualifiedName;
190 | 94606 | } else if (qualifiedName == null) {
191 | 0 | qualifiedName = localName;
192 |  | }
193 |  |
194 | 94617 | if (namespaceURI == null) {
195 | 7455 | namespaceURI = "";
196 |  | }
197 |  |
198 | 94577 | String prefix = "";
199 | 94617 | int index = qualifiedName.indexOf(":");
200 |  |
201 | 94617 | if (index > 0) {
202 | 13475 | prefix = qualifiedName.substring(0, index);
203 |  |
204 | 13475 | if (localName.trim().length() == 0) {
205 | 0 | localName = qualifiedName.substring(index + 1);
206 |  | }
207 | 81142 | } else if (localName.trim().length() == 0) {
208 | 0 | localName = qualifiedName;
209 |  | }
210 |  |
211 | 94617 | Namespace namespace = createNamespace(prefix, namespaceURI);
212 |  |
213 | 94617 | return pushQName(localName, qualifiedName, namespace, prefix);
214 |  | }
215 |  |
216 | 10455 | public QName getAttributeQName(String namespaceURI, String localName,
217 |  | String qualifiedName) {
218 | 10455 | if (qualifiedName == null) {
219 | 0 | qualifiedName = localName;
220 |  | }
221 |  |
222 | 10455 | Map map = getNamespaceCache();
223 | 10455 | QName answer = (QName) map.get(qualifiedName);
224 |  |
225 | 10455 | if (answer != null) {
226 | 9424 | return answer;
227 |  | }
228 |  |
229 | 1031 | if (localName == null) {
230 | 0 | localName = qualifiedName;
231 |  | }
232 |  |
233 | 1031 | if (namespaceURI == null) {
234 | 0 | namespaceURI = "";
235 |  | }
236 |  |
237 | 1031 | Namespace namespace = null;
238 | 1031 | String prefix = "";
239 | 1031 | int index = qualifiedName.indexOf(":");
240 |  |
241 | 1031 | if (index > 0) {
242 | 99 | prefix = qualifiedName.substring(0, index);
243 | 99 | namespace = createNamespace(prefix, namespaceURI);
244 |  |
245 | 99 | if (localName.trim().length() == 0) {
246 | 0 | localName = qualifiedName.substring(index + 1);
247 |  | }
248 |  | } else {
249 |  | // attributes with no prefix have no namespace
250 | 932 | namespace = Namespace.NO_NAMESPACE;
251 |  |
252 | 932 | if (localName.trim().length() == 0) {
253 | 0 | localName = qualifiedName;
254 |  | }
255 |  | }
256 |  |
257 | 1031 | answer = pushQName(localName, qualifiedName, namespace, prefix);
258 | 1031 | map.put(qualifiedName, answer);
259 |  |
260 | 1031 | return answer;
261 |  | }
262 |  |
263 |  | /**
264 |  | * Adds a namepace to the stack with the given prefix and URI
265 |  | *
266 |  | * @param prefix
267 |  | * DOCUMENT ME!
268 |  | * @param uri
269 |  | * DOCUMENT ME!
270 |  | */
271 | 5886 | public void push(String prefix, String uri) {
272 | 5886 | if (uri == null) {
273 | 0 | uri = "";
274 |  | }
275 |  |
276 | 5886 | Namespace namespace = createNamespace(prefix, uri);
277 | 5886 | push(namespace);
278 |  | }
279 |  |
280 |  | /**
281 |  | * Adds a new namespace to the stack
282 |  | *
283 |  | * @param prefix
284 |  | * DOCUMENT ME!
285 |  | * @param uri
286 |  | * DOCUMENT ME!
287 |  | *
288 |  | * @return DOCUMENT ME!
289 |  | */
290 | 52 | public Namespace addNamespace(String prefix, String uri) {
291 | 52 | Namespace namespace = createNamespace(prefix, uri);
292 | 52 | push(namespace);
293 |  |
294 | 52 | return namespace;
295 |  | }
296 |  |
297 |  | /**
298 |  | * Pops a namepace from the stack with the given prefix and URI
299 |  | *
300 |  | * @param prefix
301 |  | * DOCUMENT ME!
302 |  | *
303 |  | * @return DOCUMENT ME!
304 |  | */
305 | 5884 | public Namespace pop(String prefix) {
306 | 5884 | if (prefix == null) {
307 | 0 | prefix = "";
308 |  | }
309 |  |
310 | 5884 | Namespace namespace = null;
311 |  |
312 | 5986 | for (int i = namespaceStack.size() - 1; i >= 0; i--) {
313 | 5986 | Namespace ns = (Namespace) namespaceStack.get(i);
314 |  |
315 | 5986 | if (prefix.equals(ns.getPrefix())) {
316 | 5884 | remove(i);
317 | 5884 | namespace = ns;
318 |  |
319 | 5884 | break;
320 |  | }
321 |  | }
322 |  |
323 | 5884 | if (namespace == null) {
324 | 0 | System.out.println("Warning: missing namespace prefix ignored: "
325 |  | + prefix);
326 |  | }
327 |  |
328 | 5884 | return namespace;
329 |  | }
330 |  |
331 | 0 | public String toString() {
332 | 0 | return super.toString() + " Stack: " + namespaceStack.toString();
333 |  | }
334 |  |
335 | 0 | public DocumentFactory getDocumentFactory() {
336 | 0 | return documentFactory;
337 |  | }
338 |  |
339 | 0 | public void setDocumentFactory(DocumentFactory documentFactory) {
340 | 0 | this.documentFactory = documentFactory;
341 |  | }
342 |  |
343 | 18576 | public Namespace getDefaultNamespace() {
344 | 18576 | if (defaultNamespace == null) {
345 | 46 | defaultNamespace = findDefaultNamespace();
346 |  | }
347 |  |
348 | 18576 | return defaultNamespace;
349 |  | }
350 |  |
351 |  | // Implementation methods
352 |  | // -------------------------------------------------------------------------
353 |  |
354 |  | /**
355 |  | * Adds the QName to the stack of available QNames
356 |  | *
357 |  | * @param localName
358 |  | * DOCUMENT ME!
359 |  | * @param qualifiedName
360 |  | * DOCUMENT ME!
361 |  | * @param namespace
362 |  | * DOCUMENT ME!
363 |  | * @param prefix
364 |  | * DOCUMENT ME!
365 |  | *
366 |  | * @return DOCUMENT ME!
367 |  | */
368 | 95648 | protected QName pushQName(String localName, String qualifiedName,
369 |  | Namespace namespace, String prefix) {
370 | 95648 | if ((prefix == null) || (prefix.length() == 0)) {
371 | 82074 | this.defaultNamespace = null;
372 |  | }
373 |  |
374 | 95648 | return createQName(localName, qualifiedName, namespace);
375 |  | }
376 |  |
377 |  | /**
378 |  | * Factory method to creeate new QName instances. By default this method
379 |  | * interns the QName
380 |  | *
381 |  | * @param localName
382 |  | * DOCUMENT ME!
383 |  | * @param qualifiedName
384 |  | * DOCUMENT ME!
385 |  | * @param namespace
386 |  | * DOCUMENT ME!
387 |  | *
388 |  | * @return DOCUMENT ME!
389 |  | */
390 | 95648 | protected QName createQName(String localName, String qualifiedName,
391 |  | Namespace namespace) {
392 | 95648 | return documentFactory.createQName(localName, namespace);
393 |  | }
394 |  |
395 |  | /**
396 |  | * Factory method to creeate new Namespace instances. By default this method
397 |  | * interns the Namespace
398 |  | *
399 |  | * @param prefix
400 |  | * DOCUMENT ME!
401 |  | * @param namespaceURI
402 |  | * DOCUMENT ME!
403 |  | *
404 |  | * @return DOCUMENT ME!
405 |  | */
406 | 100654 | protected Namespace createNamespace(String prefix, String namespaceURI) {
407 | 100654 | return documentFactory.createNamespace(prefix, namespaceURI);
408 |  | }
409 |  |
410 |  | /**
411 |  | * Attempts to find the current default namespace on the stack right now or
412 |  | * returns null if one could not be found
413 |  | *
414 |  | * @return DOCUMENT ME!
415 |  | */
416 | 46 | protected Namespace findDefaultNamespace() {
417 | 46 | for (int i = namespaceStack.size() - 1; i >= 0; i--) {
418 | 91 | Namespace namespace = (Namespace) namespaceStack.get(i);
419 |  |
420 | 91 | if (namespace != null) {
421 | 91 | String prefix = namespace.getPrefix();
422 |  |
423 | 91 | if ((prefix == null) || (namespace.getPrefix().length() == 0)) {
424 | 30 | return namespace;
425 |  | }
426 |  | }
427 |  | }
428 |  |
429 | 16 | return null;
430 |  | }
431 |  |
432 |  | /**
433 |  | * Removes the namespace at the given index of the stack
434 |  | *
435 |  | * @param index
436 |  | * DOCUMENT ME!
437 |  | *
438 |  | * @return DOCUMENT ME!
439 |  | */
440 | 6628 | protected Namespace remove(int index) {
441 | 6628 | Namespace namespace = (Namespace) namespaceStack.remove(index);
442 | 6628 | namespaceCacheList.remove(index);
443 | 6628 | defaultNamespace = null;
444 | 6628 | currentNamespaceCache = null;
445 |  |
446 | 6628 | return namespace;
447 |  | }
448 |  |
449 | 10455 | protected Map getNamespaceCache() {
450 | 10455 | if (currentNamespaceCache == null) {
451 | 320 | int index = namespaceStack.size() - 1;
452 |  |
453 | 320 | if (index < 0) {
454 | 76 | currentNamespaceCache = rootNamespaceCache;
455 |  | } else {
456 | 244 | currentNamespaceCache = (Map) namespaceCacheList.get(index);
457 |  |
458 | 244 | if (currentNamespaceCache == null) {
459 | 212 | currentNamespaceCache = new HashMap();
460 | 212 | namespaceCacheList.set(index, currentNamespaceCache);
461 |  | }
462 |  | }
463 |  | }
464 |  |
465 | 10455 | return currentNamespaceCache;
466 |  | }
467 |  | }
468 |  |
469 |  | /*
470 |  | * Redistribution and use of this software and associated documentation
471 |  | * ("Software"), with or without modification, are permitted provided that the
472 |  | * following conditions are met:
473 |  | *
474 |  | * 1. Redistributions of source code must retain copyright statements and
475 |  | * notices. Redistributions must also contain a copy of this document.
476 |  | *
477 |  | * 2. Redistributions in binary form must reproduce the above copyright notice,
478 |  | * this list of conditions and the following disclaimer in the documentation
479 |  | * and/or other materials provided with the distribution.
480 |  | *
481 |  | * 3. The name "DOM4J" must not be used to endorse or promote products derived
482 |  | * from this Software without prior written permission of MetaStuff, Ltd. For
483 |  | * written permission, please contact dom4j-info@metastuff.com.
484 |  | *
485 |  | * 4. Products derived from this Software may not be called "DOM4J" nor may
486 |  | * "DOM4J" appear in their names without prior written permission of MetaStuff,
487 |  | * Ltd. DOM4J is a registered trademark of MetaStuff, Ltd.
488 |  | *
489 |  | * 5. Due credit should be given to the DOM4J Project - http://www.dom4j.org
490 |  | *
491 |  | * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS ``AS IS'' AND
492 |  | * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
493 |  | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
494 |  | * ARE DISCLAIMED. IN NO EVENT SHALL METASTUFF, LTD. OR ITS CONTRIBUTORS BE
495 |  | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
496 |  | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
497 |  | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
498 |  | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
499 |  | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
500 |  | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
501 |  | * POSSIBILITY OF SUCH DAMAGE.
502 |  | *
503 |  | * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
504 |  | */