Clover coverage report - dom4j - 1.5
Coverage timestamp: vr sep 3 2004 20:47:03 GMT+01:00
file stats: LOC: 378   Methods: 25
NCLOC: 228   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
NamespaceStack.java 80,9% 88,8% 88% 86,2%
coverage coverage
 1    /*
 2    * Copyright 2001-2004 (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    * $Id: NamespaceStack.java,v 1.11 2004/06/25 08:03:41 maartenc Exp $
 8    */
 9   
 10    package org.dom4j.tree;
 11   
 12    import java.util.ArrayList;
 13    import java.util.HashMap;
 14    import java.util.Map;
 15   
 16    import org.dom4j.DocumentFactory;
 17    import org.dom4j.Namespace;
 18    import org.dom4j.QName;
 19   
 20    /** NamespaceStack implements a stack of namespaces and optionally
 21    * maintains a cache of all the fully qualified names (<code>QName</code>)
 22    * which are in scope. This is useful when building or navigating a <i>dom4j</i>
 23    * document.
 24    *
 25    * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
 26    * @version $Revision: 1.11 $
 27    */
 28    public class NamespaceStack {
 29   
 30    /** The factory used to create new <code>Namespace</code> instances */
 31    private DocumentFactory documentFactory;
 32   
 33    /** The Stack of namespaces */
 34    private ArrayList namespaceStack = new ArrayList();
 35   
 36    /** The cache of qualifiedNames to QNames per namespace context */
 37    private ArrayList namespaceCacheList = new ArrayList();
 38   
 39    /** A cache of current namespace context cache of mapping from qualifiedName to QName */
 40    private Map currentNamespaceCache;
 41   
 42    /** A cache of mapping from qualifiedName to QName before any namespaces are declared */
 43    private Map rootNamespaceCache = new HashMap();
 44   
 45   
 46    /** Caches the default namespace defined via xmlns="" */
 47    private Namespace defaultNamespace;
 48   
 49   
 50  4410 public NamespaceStack() {
 51  4410 this.documentFactory = DocumentFactory.getInstance();
 52    }
 53   
 54  11638 public NamespaceStack(DocumentFactory documentFactory) {
 55  11638 this.documentFactory = documentFactory;
 56    }
 57   
 58    /** Pushes the given namespace onto the stack so that its prefix
 59    * becomes available.
 60    *
 61    * @param namespace is the <code>Namespace</code> to add to the stack.
 62    */
 63  17592 public void push(Namespace namespace) {
 64  17592 namespaceStack.add( namespace );
 65  17592 namespaceCacheList.add( null );
 66  17592 currentNamespaceCache = null;
 67  17592 String prefix = namespace.getPrefix();
 68  17592 if ( prefix == null || prefix.length() == 0 ) {
 69  4762 defaultNamespace = namespace;
 70    }
 71    }
 72   
 73    /** Pops the most recently used <code>Namespace</code> from
 74    * the stack
 75    *
 76    * @return Namespace popped from the stack
 77    */
 78  1446 public Namespace pop() {
 79  1446 return remove( namespaceStack.size() - 1 );
 80    }
 81   
 82    /** @return the number of namespaces on the stackce stack.
 83    */
 84  312382 public int size() {
 85  312382 return namespaceStack.size();
 86    }
 87   
 88    /** Clears the stack
 89    */
 90  23300 public void clear() {
 91  23300 namespaceStack.clear();
 92  23300 namespaceCacheList.clear();
 93  23300 rootNamespaceCache.clear();
 94  23300 currentNamespaceCache = null;
 95    }
 96   
 97    /** @return the namespace at the specified index on the stack
 98    */
 99  11738 public Namespace getNamespace( int index ) {
 100  11738 return (Namespace) namespaceStack.get( index );
 101    }
 102   
 103    /** @return the namespace for the given prefix or null
 104    * if it could not be found.
 105    */
 106  4212 public Namespace getNamespaceForPrefix( String prefix ) {
 107  4212 if ( prefix == null ) {
 108  0 prefix = "";
 109    }
 110  4212 for ( int i = namespaceStack.size() - 1; i >= 0; i-- ) {
 111  5430 Namespace namespace = (Namespace) namespaceStack.get(i);
 112  5430 if ( prefix.equals( namespace.getPrefix() ) ) {
 113  3014 return namespace;
 114    }
 115    }
 116  1198 return null;
 117    }
 118   
 119    /** @return the URI for the given prefix or null if it
 120    * could not be found.
 121    */
 122  24 public String getURI( String prefix ) {
 123  24 Namespace namespace = getNamespaceForPrefix( prefix );
 124  24 return ( namespace != null ) ? namespace.getURI() : null;
 125    }
 126   
 127    /** @return true if the given prefix is in the stack.
 128    */
 129  36464 public boolean contains( Namespace namespace ) {
 130  36464 String prefix = namespace.getPrefix();
 131  36464 Namespace current = null;
 132  36464 if ( prefix == null || prefix.length() == 0 ) {
 133  32282 current = getDefaultNamespace();
 134    }
 135    else {
 136  4182 current = getNamespaceForPrefix( prefix );
 137    }
 138  36464 if ( current == null ) {
 139  1226 return false;
 140    }
 141  35238 if ( current == namespace ) {
 142  35078 return true;
 143    }
 144  160 return namespace.getURI().equals( current.getURI() );
 145    }
 146   
 147  184534 public QName getQName( String namespaceURI, String localName, String qualifiedName ) {
 148  184534 if ( localName == null ) {
 149  22 localName = qualifiedName;
 150    }
 151  184512 else if ( qualifiedName == null ) {
 152  0 qualifiedName = localName;
 153    }
 154  184534 if ( namespaceURI == null ) {
 155  14910 namespaceURI = "";
 156    }
 157  184534 String prefix = "";
 158  184534 int index = qualifiedName.indexOf(":");
 159  184534 if (index > 0) {
 160  26864 prefix = qualifiedName.substring(0, index);
 161  26864 if (localName.trim().length() == 0) {
 162  0 localName = qualifiedName.substring(index+1);
 163    }
 164  157670 } else if (localName.trim().length() == 0) {
 165  0 localName = qualifiedName;
 166    }
 167  184534 Namespace namespace = createNamespace( prefix, namespaceURI );
 168  184534 return pushQName( localName, qualifiedName, namespace, prefix );
 169    }
 170   
 171  18522 public QName getAttributeQName( String namespaceURI, String localName, String qualifiedName ) {
 172  18522 if ( qualifiedName == null ) {
 173  0 qualifiedName = localName;
 174    }
 175  18522 Map map = getNamespaceCache();
 176  18522 QName answer = (QName) map.get( qualifiedName );
 177  18522 if ( answer != null ) {
 178  16544 return answer;
 179    }
 180  1978 if ( localName == null ) {
 181  0 localName = qualifiedName;
 182    }
 183  1978 if ( namespaceURI == null ) {
 184  0 namespaceURI = "";
 185    }
 186  1978 Namespace namespace = null;
 187  1978 String prefix = "";
 188  1978 int index = qualifiedName.indexOf(":");
 189  1978 if (index > 0) {
 190  192 prefix = qualifiedName.substring(0, index);
 191  192 namespace = createNamespace( prefix, namespaceURI );
 192  192 if ( localName.trim().length() == 0) {
 193  0 localName = qualifiedName.substring(index+1);
 194    }
 195    }
 196    else {
 197    // attributes with no prefix have no namespace
 198  1786 namespace = Namespace.NO_NAMESPACE;
 199  1786 if ( localName.trim().length() == 0) {
 200  0 localName = qualifiedName;
 201    }
 202    }
 203  1978 answer = pushQName( localName, qualifiedName, namespace, prefix );
 204  1978 map.put( qualifiedName, answer );
 205  1978 return answer;
 206    }
 207   
 208    /** Adds a namepace to the stack with the given prefix and URI */
 209  11742 public void push( String prefix, String uri ) {
 210  11742 if ( uri == null ) {
 211  0 uri = "";
 212    }
 213  11742 Namespace namespace = createNamespace( prefix, uri );
 214  11742 push( namespace );
 215    }
 216   
 217    /** Adds a new namespace to the stack */
 218  104 public Namespace addNamespace( String prefix, String uri ) {
 219  104 Namespace namespace = createNamespace( prefix, uri );
 220  104 push( namespace );
 221  104 return namespace;
 222    }
 223   
 224    /** Pops a namepace from the stack with the given prefix and URI */
 225  11738 public Namespace pop( String prefix ) {
 226  11738 if ( prefix == null ) {
 227  0 prefix = "";
 228    }
 229  11738 Namespace namespace = null;
 230  11738 for (int i = namespaceStack.size() - 1; i >= 0; i-- ) {
 231  11990 Namespace ns = (Namespace) namespaceStack.get(i);
 232  11990 if ( prefix.equals( ns.getPrefix() ) ) {
 233  11714 remove(i);
 234  11714 namespace = ns;
 235  11714 break;
 236    }
 237    }
 238  11738 if ( namespace == null ) {
 239  24 System.out.println( "Warning: missing namespace prefix ignored: " + prefix );
 240    }
 241  11738 return namespace;
 242    }
 243   
 244  0 public String toString() {
 245  0 return super.toString() + " Stack: " + namespaceStack.toString();
 246    }
 247   
 248  0 public DocumentFactory getDocumentFactory() {
 249  0 return documentFactory;
 250    }
 251   
 252  0 public void setDocumentFactory(DocumentFactory documentFactory) {
 253  0 this.documentFactory = documentFactory;
 254    }
 255   
 256  32284 public Namespace getDefaultNamespace() {
 257  32284 if ( defaultNamespace == null ) {
 258  80 defaultNamespace = findDefaultNamespace();
 259    }
 260  32284 return defaultNamespace;
 261    }
 262   
 263    // Implementation methods
 264    //-------------------------------------------------------------------------
 265   
 266    /** Adds the QName to the stack of available QNames
 267    */
 268  186512 protected QName pushQName( String localName, String qualifiedName, Namespace namespace, String prefix ) {
 269  186512 if ( prefix == null || prefix.length() == 0 ) {
 270  159456 this.defaultNamespace = null;
 271    }
 272  186512 return createQName( localName, qualifiedName, namespace );
 273    }
 274   
 275    /** Factory method to creeate new QName instances. By default this method
 276    * interns the QName
 277    */
 278  186512 protected QName createQName( String localName, String qualifiedName, Namespace namespace ) {
 279  186512 return documentFactory.createQName( localName, namespace );
 280    }
 281   
 282    /** Factory method to creeate new Namespace instances. By default this method
 283    * interns the Namespace
 284    */
 285  196572 protected Namespace createNamespace( String prefix, String namespaceURI ) {
 286  196572 return documentFactory.createNamespace( prefix, namespaceURI );
 287    }
 288   
 289    /** Attempts to find the current default namespace on the stack right now or returns null if one
 290    * could not be found
 291    */
 292  80 protected Namespace findDefaultNamespace() {
 293  80 for ( int i = namespaceStack.size() - 1; i >= 0; i-- ) {
 294  154 Namespace namespace = (Namespace) namespaceStack.get(i);
 295  154 if ( namespace != null ) {
 296  154 String prefix = namespace.getPrefix();
 297  154 if ( prefix == null || namespace.getPrefix().length() == 0 ) {
 298  48 return namespace;
 299    }
 300    }
 301    }
 302  32 return null;
 303    }
 304   
 305    /** Removes the namespace at the given index of the stack */
 306  13160 protected Namespace remove(int index) {
 307  13160 Namespace namespace = (Namespace) namespaceStack.remove(index);
 308  13160 namespaceCacheList.remove(index);
 309  13160 defaultNamespace = null;
 310  13160 currentNamespaceCache = null;
 311  13160 return namespace;
 312    }
 313   
 314  18522 protected Map getNamespaceCache() {
 315  18522 if ( currentNamespaceCache == null ) {
 316  616 int index = namespaceStack.size() - 1;
 317  616 if ( index < 0 ) {
 318  146 currentNamespaceCache = rootNamespaceCache;
 319    }
 320    else {
 321  470 currentNamespaceCache = (Map) namespaceCacheList.get(index);
 322  470 if ( currentNamespaceCache == null ) {
 323  410 currentNamespaceCache = new HashMap();
 324  410 namespaceCacheList.set(index, currentNamespaceCache);
 325    }
 326    }
 327    }
 328  18522 return currentNamespaceCache;
 329    }
 330    }
 331   
 332   
 333   
 334   
 335    /*
 336    * Redistribution and use of this software and associated documentation
 337    * ("Software"), with or without modification, are permitted provided
 338    * that the following conditions are met:
 339    *
 340    * 1. Redistributions of source code must retain copyright
 341    * statements and notices. Redistributions must also contain a
 342    * copy of this document.
 343    *
 344    * 2. Redistributions in binary form must reproduce the
 345    * above copyright notice, this list of conditions and the
 346    * following disclaimer in the documentation and/or other
 347    * materials provided with the distribution.
 348    *
 349    * 3. The name "DOM4J" must not be used to endorse or promote
 350    * products derived from this Software without prior written
 351    * permission of MetaStuff, Ltd. For written permission,
 352    * please contact dom4j-info@metastuff.com.
 353    *
 354    * 4. Products derived from this Software may not be called "DOM4J"
 355    * nor may "DOM4J" appear in their names without prior written
 356    * permission of MetaStuff, Ltd. DOM4J is a registered
 357    * trademark of MetaStuff, Ltd.
 358    *
 359    * 5. Due credit should be given to the DOM4J Project -
 360    * http://www.dom4j.org
 361    *
 362    * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS
 363    * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
 364    * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 365    * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 366    * METASTUFF, LTD. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 367    * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 368    * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 369    * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 370    * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 371    * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 372    * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 373    * OF THE POSSIBILITY OF SUCH DAMAGE.
 374    *
 375    * Copyright 2001-2004 (C) MetaStuff, Ltd. All Rights Reserved.
 376    *
 377    * $Id: NamespaceStack.java,v 1.11 2004/06/25 08:03:41 maartenc Exp $
 378    */