Coverage Report - org.jaxen.dom4j.DocumentNavigator
 
Classes in this File Line Coverage Branch Coverage Complexity
DocumentNavigator
80%
114/142
88%
28/32
2.405
DocumentNavigator$Singleton
100%
2/2
N/A
2.405
 
 1  
 package org.jaxen.dom4j;
 2  
 
 3  
 /*
 4  
  * $Header: /home/projects/jaxen/scm/jaxen/src/java/main/org/jaxen/dom4j/DocumentNavigator.java,v 1.33 2006/07/03 13:17:30 elharo Exp $
 5  
  * $Revision: 1.33 $
 6  
  * $Date: 2006/07/03 13:17:30 $
 7  
  *
 8  
  * ====================================================================
 9  
  *
 10  
  * Copyright 2000-2005 bob mcwhirter & James Strachan.
 11  
  * All rights reserved.
 12  
  *
 13  
  *
 14  
  * Redistribution and use in source and binary forms, with or without
 15  
  * modification, are permitted provided that the following conditions are
 16  
  * met:
 17  
  * 
 18  
  *   * Redistributions of source code must retain the above copyright
 19  
  *     notice, this list of conditions and the following disclaimer.
 20  
  * 
 21  
  *   * Redistributions in binary form must reproduce the above copyright
 22  
  *     notice, this list of conditions and the following disclaimer in the
 23  
  *     documentation and/or other materials provided with the distribution.
 24  
  * 
 25  
  *   * Neither the name of the Jaxen Project nor the names of its
 26  
  *     contributors may be used to endorse or promote products derived 
 27  
  *     from this software without specific prior written permission.
 28  
  * 
 29  
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 30  
  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 31  
  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 32  
  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 33  
  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 34  
  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 35  
  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 36  
  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 37  
  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 38  
  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 39  
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 40  
  *
 41  
  * ====================================================================
 42  
  * This software consists of voluntary contributions made by many
 43  
  * individuals on behalf of the Jaxen Project and was originally
 44  
  * created by bob mcwhirter <bob@werken.com> and
 45  
  * James Strachan <jstrachan@apache.org>.  For more information on the
 46  
  * Jaxen Project, please see <http://www.jaxen.org/>.
 47  
  *
 48  
  * $Id: DocumentNavigator.java,v 1.33 2006/07/03 13:17:30 elharo Exp $
 49  
 */
 50  
 
 51  
 import java.util.ArrayList;
 52  
 import java.util.HashSet;
 53  
 import java.util.Iterator;
 54  
 import java.util.List;
 55  
 
 56  
 import org.dom4j.Attribute;
 57  
 import org.dom4j.Branch;
 58  
 import org.dom4j.CDATA;
 59  
 import org.dom4j.Comment;
 60  
 import org.dom4j.Document;
 61  
 import org.dom4j.DocumentException;
 62  
 import org.dom4j.Element;
 63  
 import org.dom4j.Namespace;
 64  
 import org.dom4j.Node;
 65  
 import org.dom4j.ProcessingInstruction;
 66  
 import org.dom4j.QName;
 67  
 import org.dom4j.Text;
 68  
 import org.dom4j.io.SAXReader;
 69  
 import org.jaxen.DefaultNavigator;
 70  
 import org.jaxen.FunctionCallException;
 71  
 import org.jaxen.NamedAccessNavigator;
 72  
 import org.jaxen.Navigator;
 73  
 import org.jaxen.XPath;
 74  
 import org.jaxen.JaxenConstants;
 75  
 import org.jaxen.saxpath.SAXPathException;
 76  
 import org.jaxen.util.SingleObjectIterator;
 77  
 
 78  
 /** 
 79  
  * Interface for navigating around the DOM4J object model.
 80  
  *
 81  
  * <p>
 82  
  * This class is not intended for direct usage, but is
 83  
  * used by the Jaxen engine during evaluation.
 84  
  * </p>
 85  
  *
 86  
  * @see XPath
 87  
  *
 88  
  * @author <a href="mailto:bob@werken.com">bob mcwhirter</a>
 89  
  * @author Stephen Colebourne
 90  
  */
 91  588
 public class DocumentNavigator extends DefaultNavigator implements NamedAccessNavigator
 92  
 {
 93  
     
 94  
     /**
 95  
      * 
 96  
      */
 97  
     private static final long serialVersionUID = 5582300797286535936L;
 98  
     private transient SAXReader reader;
 99  
 
 100  
     /** Singleton implementation.
 101  
      */
 102  588
     private static class Singleton
 103  
     {
 104  
         /** Singleton instance.
 105  
          */
 106  4
         private static DocumentNavigator instance = new DocumentNavigator();
 107  
     }
 108  
 
 109  
     /** Retrieve the singleton instance of this <code>DocumentNavigator</code>.
 110  
      */
 111  
     public static Navigator getInstance()
 112  
     {
 113  32
         return Singleton.instance;
 114  
     }
 115  
 
 116  
     public boolean isElement(Object obj)
 117  
     {
 118  223808
         return obj instanceof Element;
 119  
     }
 120  
 
 121  
     public boolean isComment(Object obj)
 122  
     {
 123  2222
         return obj instanceof Comment;
 124  
     }
 125  
 
 126  
     public boolean isText(Object obj)
 127  
     {
 128  151202
         return ( obj instanceof Text 
 129  
                  ||
 130  
                  obj instanceof CDATA );
 131  
     }
 132  
 
 133  
     public boolean isAttribute(Object obj)
 134  
     {
 135  8836
         return obj instanceof Attribute;
 136  
     }
 137  
 
 138  
     public boolean isProcessingInstruction(Object obj)
 139  
     {
 140  2142
         return obj instanceof ProcessingInstruction;
 141  
     }
 142  
 
 143  
     public boolean isDocument(Object obj)
 144  
     {
 145  2344
         return obj instanceof Document;
 146  
     }
 147  
 
 148  
     public boolean isNamespace(Object obj)
 149  
     {
 150  8060
         return obj instanceof Namespace;
 151  
     }
 152  
 
 153  
     public String getElementName(Object obj)
 154  
     {
 155  74140
         Element elem = (Element) obj;
 156  
 
 157  74140
         return elem.getName();
 158  
     }
 159  
 
 160  
     public String getElementNamespaceUri(Object obj)
 161  
     {
 162  73678
         Element elem = (Element) obj;
 163  
         
 164  73678
         String uri = elem.getNamespaceURI();
 165  73678
         if ( uri == null)
 166  0
             return "";
 167  
         else
 168  73678
             return uri;
 169  
     }
 170  
 
 171  
     public String getElementQName(Object obj)
 172  
     {
 173  52
         Element elem = (Element) obj;
 174  
 
 175  52
         return elem.getQualifiedName();
 176  
     }
 177  
 
 178  
     public String getAttributeName(Object obj)
 179  
     {
 180  60
         Attribute attr = (Attribute) obj;
 181  
 
 182  60
         return attr.getName();
 183  
     }
 184  
 
 185  
     public String getAttributeNamespaceUri(Object obj)
 186  
     {
 187  60
         Attribute attr = (Attribute) obj;
 188  
 
 189  60
         String uri = attr.getNamespaceURI();
 190  60
         if ( uri == null)
 191  0
             return "";
 192  
         else
 193  60
             return uri;
 194  
     }
 195  
 
 196  
     public String getAttributeQName(Object obj)
 197  
     {
 198  0
         Attribute attr = (Attribute) obj;
 199  
 
 200  0
         return attr.getQualifiedName();
 201  
     }
 202  
 
 203  
     public Iterator getChildAxisIterator(Object contextNode)
 204  
     {
 205  233324
         Iterator result = null;
 206  233324
         if ( contextNode instanceof Branch )
 207  
         {
 208  81376
             Branch node = (Branch) contextNode;
 209  81376
             result = node.nodeIterator();
 210  
         }
 211  233324
         if (result != null) {
 212  81376
             return result;
 213  
         }
 214  151948
         return JaxenConstants.EMPTY_ITERATOR;
 215  
     }
 216  
 
 217  
     /**
 218  
      * Retrieves an <code>Iterator</code> over the child elements that
 219  
      * match the supplied name.
 220  
      *
 221  
      * @param contextNode      the origin context node
 222  
      * @param localName        the local name of the children to return, always present
 223  
      * @param namespacePrefix  the prefix of the namespace of the children to return
 224  
      * @param namespaceURI     the uri of the namespace of the children to return
 225  
      * 
 226  
      * @return an Iterator that traverses the named children, or null if none
 227  
      */
 228  
     public Iterator getChildAxisIterator(
 229  
             Object contextNode, String localName, String namespacePrefix, String namespaceURI) {
 230  
 
 231  4724
         if ( contextNode instanceof Element ) {
 232  1868
             Element node = (Element) contextNode;
 233  1868
             return node.elementIterator(QName.get(localName, namespacePrefix, namespaceURI));
 234  
         }
 235  2856
         if ( contextNode instanceof Document ) {
 236  236
             Document node = (Document) contextNode;
 237  236
             Element el = node.getRootElement();
 238  236
             if (el == null || el.getName().equals(localName) == false) {
 239  32
                 return JaxenConstants.EMPTY_ITERATOR;
 240  
             }
 241  204
             if (namespaceURI != null) {
 242  20
                 if (namespaceURI.equals(el.getNamespaceURI()) == false) {
 243  2
                     return JaxenConstants.EMPTY_ITERATOR;
 244  
                 }
 245  
             }
 246  202
             return new SingleObjectIterator(el);
 247  
         }
 248  
 
 249  2620
         return JaxenConstants.EMPTY_ITERATOR;
 250  
     }
 251  
 
 252  
     public Iterator getParentAxisIterator(Object contextNode)
 253  
     {
 254  28
         if ( contextNode instanceof Document )
 255  
         {
 256  2
             return JaxenConstants.EMPTY_ITERATOR;
 257  
         }
 258  
 
 259  26
         Node node = (Node) contextNode;
 260  
 
 261  26
         Object parent = node.getParent();
 262  
 
 263  26
         if ( parent == null )
 264  
         {
 265  10
             parent = node.getDocument();
 266  
         }
 267  
         
 268  26
         return new SingleObjectIterator( parent );
 269  
     }
 270  
 
 271  
     public Iterator getAttributeAxisIterator(Object contextNode)
 272  
     {
 273  102
         if ( ! ( contextNode instanceof Element ) )
 274  
         {
 275  0
             return JaxenConstants.EMPTY_ITERATOR;
 276  
         }
 277  
 
 278  102
         Element elem = (Element) contextNode;
 279  
 
 280  102
         return elem.attributeIterator();
 281  
     }
 282  
 
 283  
     /**
 284  
      * Retrieves an <code>Iterator</code> over the attribute elements that
 285  
      * match the supplied name.
 286  
      *
 287  
      * @param contextNode  the origin context node
 288  
      * @param localName  the local name of the attributes to return, always present
 289  
      * @param namespacePrefix  the prefix of the namespace of the attributes to return
 290  
      * @param namespaceURI  the URI of the namespace of the attributes to return
 291  
      * @return an Iterator that traverses the named attributes, not null
 292  
      */
 293  
     public Iterator getAttributeAxisIterator(
 294  
             Object contextNode, String localName, String namespacePrefix, String namespaceURI) {
 295  
 
 296  1188
         if ( contextNode instanceof Element ) {
 297  1096
             Element node = (Element) contextNode;
 298  1096
             Attribute attr = node.attribute(QName.get(localName, namespacePrefix, namespaceURI));
 299  1096
             if (attr == null) {
 300  462
                 return JaxenConstants.EMPTY_ITERATOR;
 301  
             }
 302  634
             return new SingleObjectIterator(attr);
 303  
         }
 304  92
         return JaxenConstants.EMPTY_ITERATOR;
 305  
     }
 306  
         
 307  
     public Iterator getNamespaceAxisIterator(Object contextNode)
 308  
     {
 309  334
         if ( ! ( contextNode instanceof Element ) )
 310  
         {
 311  208
             return JaxenConstants.EMPTY_ITERATOR;
 312  
         }
 313  
 
 314  126
         Element element = (Element) contextNode;
 315  126
         List nsList = new ArrayList();
 316  126
         HashSet prefixes = new HashSet();
 317  456
         for ( Element context = element; context != null; context = context.getParent() ) {
 318  330
             List declaredNS = new ArrayList(context.declaredNamespaces());
 319  330
             declaredNS.add(context.getNamespace());
 320  
 
 321  330
             for ( Iterator iter = context.attributes().iterator(); iter.hasNext(); )
 322  
             {
 323  164
                 Attribute attr = (Attribute) iter.next();
 324  164
                 declaredNS.add(attr.getNamespace());
 325  164
             }
 326  
 
 327  330
             for ( Iterator iter = declaredNS.iterator(); iter.hasNext(); )
 328  
             {
 329  706
                 Namespace namespace = (Namespace) iter.next();
 330  706
                 if (namespace != Namespace.NO_NAMESPACE)
 331  
                 {
 332  294
                     String prefix = namespace.getPrefix();
 333  294
                     if ( ! prefixes.contains( prefix ) ) {
 334  222
                         prefixes.add( prefix );
 335  222
                         nsList.add( namespace.asXPathResult( element ) );
 336  
                     }
 337  
                 }
 338  706
             }
 339  
         }
 340  126
         nsList.add( Namespace.XML_NAMESPACE.asXPathResult( element ) );
 341  126
         return nsList.iterator();
 342  
     }
 343  
 
 344  
     public Object getDocumentNode(Object contextNode)
 345  
     {
 346  534
         if ( contextNode instanceof Document ) 
 347  
         {
 348  398
             return contextNode;
 349  
         }
 350  136
         else if ( contextNode instanceof Node ) 
 351  
         {
 352  136
             Node node = (Node) contextNode;
 353  136
             return node.getDocument();
 354  
         }
 355  0
         return null;
 356  
     }
 357  
 
 358  
     /** Returns a parsed form of the given XPath string, which will be suitable
 359  
      *  for queries on DOM4J documents.
 360  
      */
 361  
     public XPath parseXPath (String xpath) throws SAXPathException
 362  
     {
 363  14
         return new Dom4jXPath(xpath);
 364  
     }
 365  
 
 366  
     public Object getParentNode(Object contextNode)
 367  
     {
 368  50314
         if ( contextNode instanceof Node ) 
 369  
         {
 370  50314
             Node node = (Node) contextNode;
 371  50314
             Object answer = node.getParent();
 372  50314
             if ( answer == null ) 
 373  
             {
 374  19680
                 answer = node.getDocument();
 375  19680
                 if (answer == contextNode) {
 376  9804
                     return null;
 377  
                 }
 378  
             }
 379  40510
             return answer;            
 380  
         }
 381  0
         return null;
 382  
     }
 383  
 
 384  
     public String getTextStringValue(Object obj)
 385  
     {
 386  28
         return getNodeStringValue( (Node) obj );
 387  
     }
 388  
 
 389  
     public String getElementStringValue(Object obj)
 390  
     {
 391  260
         return getNodeStringValue( (Node) obj );
 392  
     }
 393  
 
 394  
     public String getAttributeStringValue(Object obj)
 395  
     {
 396  574
         return getNodeStringValue( (Node) obj );
 397  
     }
 398  
 
 399  
     private String getNodeStringValue(Node node)
 400  
     {
 401  862
         return node.getStringValue();
 402  
     }
 403  
 
 404  
     public String getNamespaceStringValue(Object obj)
 405  
     {
 406  0
         Namespace ns = (Namespace) obj;
 407  
 
 408  0
         return ns.getURI();
 409  
     }
 410  
 
 411  
     public String getNamespacePrefix(Object obj)
 412  
     {
 413  234
         Namespace ns = (Namespace) obj;
 414  
 
 415  234
         return ns.getPrefix();
 416  
     }
 417  
 
 418  
     public String getCommentStringValue(Object obj)
 419  
     {
 420  0
         Comment cmt = (Comment) obj;
 421  
 
 422  0
         return cmt.getText();
 423  
     }
 424  
     
 425  
     public String translateNamespacePrefixToUri(String prefix, Object context)
 426  
     {
 427  0
         Element element = null;
 428  0
         if ( context instanceof Element ) 
 429  
         {
 430  0
             element = (Element) context;
 431  0
         }
 432  0
         else if ( context instanceof Node )
 433  
         {
 434  0
             Node node = (Node) context;
 435  0
             element = node.getParent();
 436  
         }
 437  0
         if ( element != null )
 438  
         {
 439  0
             Namespace namespace = element.getNamespaceForPrefix( prefix );
 440  
 
 441  0
             if ( namespace != null ) 
 442  
             {
 443  0
                 return namespace.getURI();
 444  
             }
 445  
         }
 446  0
         return null;
 447  
     }
 448  
     
 449  
     public short getNodeType(Object node) 
 450  
     {
 451  50
         if ( node instanceof Node )
 452  
         {
 453  50
             return ((Node) node).getNodeType();
 454  
         }
 455  0
         return 0;
 456  
     }
 457  
     
 458  
     public Object getDocument(String uri) throws FunctionCallException
 459  
     {
 460  
         try
 461  
         {
 462  138
             return getSAXReader().read( uri );
 463  
         }
 464  0
         catch (DocumentException e)
 465  
         {
 466  0
             throw new FunctionCallException("Failed to parse document for URI: " + uri, e);
 467  
         }
 468  
     }
 469  
 
 470  
     public String getProcessingInstructionTarget(Object obj)
 471  
     {
 472  12
         ProcessingInstruction pi = (ProcessingInstruction) obj;
 473  
 
 474  12
         return pi.getTarget();
 475  
     }
 476  
 
 477  
     public String getProcessingInstructionData(Object obj)
 478  
     {
 479  6
         ProcessingInstruction pi = (ProcessingInstruction) obj;
 480  
 
 481  6
         return pi.getText();
 482  
     }
 483  
     
 484  
     // Properties
 485  
     //-------------------------------------------------------------------------    
 486  
     public SAXReader getSAXReader()
 487  
     {
 488  138
         if ( reader == null ) 
 489  
         {
 490  136
             reader = new SAXReader();
 491  136
             reader.setMergeAdjacentText( true );
 492  
         }
 493  138
         return reader;
 494  
     }
 495  
     
 496  
     public void setSAXReader(SAXReader reader)
 497  
     {
 498  0
         this.reader = reader;
 499  0
     }
 500  
     
 501  
 }