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