Coverage Report - org.jaxen.jdom.DocumentNavigator
 
Classes in this File Line Coverage Branch Coverage Complexity
DocumentNavigator
74%
144/195
79%
44/56
3.469
DocumentNavigator$Singleton
100%
2/2
N/A
3.469
 
 1  
 package org.jaxen.jdom;
 2  
 
 3  
 /*
 4  
  * $Header: /home/projects/jaxen/scm/jaxen/src/java/main/org/jaxen/jdom/DocumentNavigator.java,v 1.36 2006/09/21 11:48:05 elharo Exp $
 5  
  * $Revision: 1.36 $
 6  
  * $Date: 2006/09/21 11:48:05 $
 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.36 2006/09/21 11:48:05 elharo Exp $
 49  
 */
 50  
 
 51  
 import java.util.HashMap;
 52  
 import java.util.Iterator;
 53  
 import java.util.List;
 54  
 import java.util.Map;
 55  
 
 56  
 import org.jaxen.DefaultNavigator;
 57  
 import org.jaxen.FunctionCallException;
 58  
 import org.jaxen.NamedAccessNavigator;
 59  
 import org.jaxen.Navigator;
 60  
 import org.jaxen.XPath;
 61  
 import org.jaxen.JaxenConstants;
 62  
 import org.jaxen.saxpath.SAXPathException;
 63  
 import org.jaxen.util.SingleObjectIterator;
 64  
 import org.jdom.Attribute;
 65  
 import org.jdom.CDATA;
 66  
 import org.jdom.Comment;
 67  
 import org.jdom.Document;
 68  
 import org.jdom.Element;
 69  
 import org.jdom.Namespace;
 70  
 import org.jdom.ProcessingInstruction;
 71  
 import org.jdom.Text;
 72  
 import org.jdom.input.SAXBuilder;
 73  
 
 74  
 /** 
 75  
  * Interface for navigating around the JDOM object model.
 76  
  *
 77  
  * <p>
 78  
  * This class is not intended for direct usage, but is
 79  
  * used by the Jaxen engine during evaluation.
 80  
  * </p>
 81  
  *
 82  
  * @see XPath
 83  
  *
 84  
  * @author <a href="mailto:bob@werken.com">bob mcwhirter</a>
 85  
  * @author Stephen Colebourne
 86  
  */
 87  586
 public class DocumentNavigator extends DefaultNavigator implements NamedAccessNavigator
 88  
 {
 89  
     /**
 90  
      * 
 91  
      */
 92  
     private static final long serialVersionUID = -1636727587303584165L;
 93  
 
 94  
     /** Singleton implementation.
 95  
      */
 96  586
     private static class Singleton
 97  
     {
 98  
         /** Singleton instance.
 99  
          */
 100  4
         private static DocumentNavigator instance = new DocumentNavigator();
 101  
     }
 102  
 
 103  
     public static Navigator getInstance()
 104  
     {
 105  30
         return Singleton.instance;
 106  
     }
 107  
 
 108  
     public boolean isElement(Object obj)
 109  
     {
 110  223840
         return obj instanceof Element;
 111  
     }
 112  
 
 113  
     public boolean isComment(Object obj)
 114  
     {
 115  2246
         return obj instanceof Comment;
 116  
     }
 117  
 
 118  
     public boolean isText(Object obj)
 119  
     {
 120  151232
         return ( obj instanceof Text
 121  
                  ||
 122  
                  obj instanceof CDATA );
 123  
     }
 124  
 
 125  
     public boolean isAttribute(Object obj)
 126  
     {
 127  8868
         return obj instanceof Attribute;
 128  
     }
 129  
 
 130  
     public boolean isProcessingInstruction(Object obj)
 131  
     {
 132  2186
         return obj instanceof ProcessingInstruction;
 133  
     }
 134  
 
 135  
     public boolean isDocument(Object obj)
 136  
     {
 137  2378
         return obj instanceof Document;
 138  
     }
 139  
 
 140  
     public boolean isNamespace(Object obj)
 141  
     {
 142  8092
         return obj instanceof Namespace || obj instanceof XPathNamespace;
 143  
     }
 144  
 
 145  
     public String getElementName(Object obj)
 146  
     {
 147  74140
         Element elem = (Element) obj;
 148  
 
 149  74140
         return elem.getName();
 150  
     }
 151  
 
 152  
     public String getElementNamespaceUri(Object obj)
 153  
     {
 154  73678
         Element elem = (Element) obj;
 155  
         
 156  73678
         String uri = elem.getNamespaceURI();
 157  73678
         if ( uri != null && uri.length() == 0 ) 
 158  73622
             return null;
 159  
         else
 160  56
             return uri;
 161  
     }
 162  
 
 163  
     public String getAttributeName(Object obj)
 164  
     {
 165  60
         Attribute attr = (Attribute) obj;
 166  
 
 167  60
         return attr.getName();
 168  
     }
 169  
 
 170  
     public String getAttributeNamespaceUri(Object obj)
 171  
     {
 172  60
         Attribute attr = (Attribute) obj;
 173  
 
 174  60
         String uri = attr.getNamespaceURI();
 175  60
         if ( uri != null && uri.length() == 0 ) 
 176  0
             return null;
 177  
         else
 178  60
             return uri;
 179  
     }
 180  
 
 181  
     public Iterator getChildAxisIterator(Object contextNode)
 182  
     {
 183  233232
         if ( contextNode instanceof Element )
 184  
         {
 185  81008
             return ((Element)contextNode).getContent().iterator();
 186  
         }
 187  152224
         else if ( contextNode instanceof Document )
 188  
         {
 189  360
             return ((Document)contextNode).getContent().iterator();
 190  
         }
 191  
 
 192  151864
         return JaxenConstants.EMPTY_ITERATOR;
 193  
     }
 194  
 
 195  
     /**
 196  
      * Retrieves an <code>Iterator</code> over the child elements that
 197  
      * match the supplied local name and namespace URI.
 198  
      *
 199  
      * @param contextNode      the origin context node
 200  
      * @param localName        the local name of the children to return, always present
 201  
      * @param namespacePrefix  ignored; prefixes are not used when matching in XPath
 202  
      * @param namespaceURI     the URI of the namespace of the children to return
 203  
      * @return an Iterator     that traverses the named children, or null if none
 204  
      */
 205  
     public Iterator getChildAxisIterator(
 206  
             Object contextNode, String localName, String namespacePrefix, String namespaceURI) {
 207  
 
 208  4732
         if ( contextNode instanceof Element ) {
 209  1870
             Element node = (Element) contextNode;
 210  1870
             if (namespaceURI == null) {
 211  1852
                 return node.getChildren(localName).iterator();
 212  
             }
 213  18
             return node.getChildren(localName, Namespace.getNamespace(namespacePrefix, namespaceURI)).iterator();
 214  
         }
 215  2862
         if ( contextNode instanceof Document ) {
 216  236
             Document node = (Document) contextNode;
 217  
             
 218  236
             Element el = node.getRootElement();
 219  236
             if (el.getName().equals(localName) == false) {
 220  32
                 return JaxenConstants.EMPTY_ITERATOR;
 221  
             }
 222  204
             if (namespaceURI != null) {
 223  
                 // JDOM's equals method does not consider the prefix when comparing namespace objects
 224  20
                 if (!Namespace.getNamespace(namespacePrefix, namespaceURI).equals(el.getNamespace())) {
 225  2
                     return JaxenConstants.EMPTY_ITERATOR;
 226  
                 }
 227  
             }
 228  184
             else if(el.getNamespace() != Namespace.NO_NAMESPACE) { 
 229  4
                 return JaxenConstants.EMPTY_ITERATOR; 
 230  
             }
 231  
             
 232  198
             return new SingleObjectIterator(el);
 233  
         }
 234  
 
 235  2626
         return JaxenConstants.EMPTY_ITERATOR;
 236  
     }
 237  
     
 238  
     public Iterator getNamespaceAxisIterator(Object contextNode)
 239  
     {
 240  256
         if ( ! ( contextNode instanceof Element ) )
 241  
         {
 242  148
             return JaxenConstants.EMPTY_ITERATOR;
 243  
         }
 244  
 
 245  108
         Element elem = (Element) contextNode;
 246  
 
 247  108
         Map nsMap = new HashMap();
 248  
 
 249  108
         Element current = elem;
 250  
 
 251  388
         while ( current != null ) {
 252  
         
 253  280
             Namespace ns = current.getNamespace();
 254  
             
 255  280
             if ( ns != Namespace.NO_NAMESPACE ) {
 256  66
                 if ( !nsMap.containsKey(ns.getPrefix()) )
 257  66
                     nsMap.put( ns.getPrefix(), new XPathNamespace(elem, ns) );
 258  
             }
 259  
         
 260  280
             Iterator additional = current.getAdditionalNamespaces().iterator();
 261  
 
 262  460
             while ( additional.hasNext() ) {
 263  
 
 264  180
                 ns = (Namespace)additional.next();
 265  180
                 if ( !nsMap.containsKey(ns.getPrefix()) )
 266  120
                     nsMap.put( ns.getPrefix(), new XPathNamespace(elem, ns) );
 267  
             }
 268  
 
 269  280
             Iterator attributes = current.getAttributes().iterator();
 270  
 
 271  420
             while ( attributes.hasNext() ) {
 272  
 
 273  140
                 Attribute attribute = (Attribute)attributes.next();
 274  
 
 275  140
                 Namespace attrNS = attribute.getNamespace();
 276  
             
 277  140
                 if ( attrNS != Namespace.NO_NAMESPACE ) {
 278  4
                     if ( !nsMap.containsKey(attrNS.getPrefix()) )
 279  4
                         nsMap.put( attrNS.getPrefix(), new XPathNamespace(elem, attrNS) );
 280  
                 }
 281  140
             }
 282  
 
 283  280
             if (current.getParent() instanceof Element) {
 284  172
                 current = (Element)current.getParent();
 285  172
             } else {
 286  108
                 current = null;
 287  
             }
 288  280
         }
 289  
 
 290  108
         nsMap.put( "xml", new XPathNamespace(elem, Namespace.XML_NAMESPACE) );
 291  
 
 292  108
         return nsMap.values().iterator();
 293  
     }
 294  
 
 295  
     public Iterator getParentAxisIterator(Object contextNode)
 296  
     {
 297  50360
         Object parent = null;
 298  
 
 299  50360
         if ( contextNode instanceof Document )
 300  
         {
 301  9838
             return JaxenConstants.EMPTY_ITERATOR;
 302  
         }
 303  40522
         else if ( contextNode instanceof Element )
 304  
         {
 305  39550
             parent = ((Element)contextNode).getParent();
 306  
 
 307  39550
             if ( parent == null )
 308  
             {
 309  0
                 if ( ((Element)contextNode).isRootElement() )
 310  
                 {
 311  0
                     parent = ((Element)contextNode).getDocument();
 312  0
                 }
 313  
             }
 314  
         }
 315  972
         else if ( contextNode instanceof Attribute )
 316  
         {
 317  148
             parent = ((Attribute)contextNode).getParent();
 318  148
         }
 319  824
         else if ( contextNode instanceof XPathNamespace )
 320  
         {
 321  684
             parent = ((XPathNamespace)contextNode).getJDOMElement();
 322  684
         }
 323  140
         else if ( contextNode instanceof ProcessingInstruction )
 324  
         {
 325  40
             parent = ((ProcessingInstruction)contextNode).getParent();
 326  40
         }
 327  100
         else if ( contextNode instanceof Comment )
 328  
         {
 329  40
             parent = ((Comment)contextNode).getParent();
 330  40
         }
 331  60
         else if ( contextNode instanceof Text )
 332  
         {
 333  60
             parent = ((Text)contextNode).getParent();
 334  
         }
 335  
         
 336  40522
         if ( parent != null )
 337  
         {
 338  40522
             return new SingleObjectIterator( parent );
 339  
         }
 340  
 
 341  0
         return JaxenConstants.EMPTY_ITERATOR;
 342  
     }
 343  
 
 344  
     public Iterator getAttributeAxisIterator(Object contextNode)
 345  
     {
 346  102
         if ( ! ( contextNode instanceof Element ) )
 347  
         {
 348  0
             return JaxenConstants.EMPTY_ITERATOR;
 349  
         }
 350  
 
 351  102
         Element elem = (Element) contextNode;
 352  
 
 353  102
         return elem.getAttributes().iterator();
 354  
     }
 355  
 
 356  
     /**
 357  
      * Retrieves an <code>Iterator</code> over the attribute elements that
 358  
      * match the supplied name.
 359  
      *
 360  
      * @param contextNode      the origin context node
 361  
      * @param localName        the local name of the attributes to return, always present
 362  
      * @param namespacePrefix  the prefix of the namespace of the attributes to return
 363  
      * @param namespaceURI     the URI of the namespace of the attributes to return
 364  
      * @return an Iterator     that traverses the named attributes, not null
 365  
      */
 366  
     public Iterator getAttributeAxisIterator(
 367  
             Object contextNode, String localName, String namespacePrefix, String namespaceURI) {
 368  
 
 369  1188
         if ( contextNode instanceof Element ) {
 370  1096
             Element node = (Element) contextNode;
 371  1096
             Namespace namespace = (namespaceURI == null ? Namespace.NO_NAMESPACE : 
 372  
                                     Namespace.getNamespace(namespacePrefix, namespaceURI));
 373  1096
             Attribute attr = node.getAttribute(localName, namespace);
 374  1096
             if (attr != null) {
 375  634
                 return new SingleObjectIterator(attr);
 376  
             }
 377  
         }
 378  554
         return JaxenConstants.EMPTY_ITERATOR;
 379  
     }
 380  
 
 381  
     /** Returns a parsed form of the given XPath string, which will be suitable
 382  
      *  for queries on JDOM documents.
 383  
      */
 384  
     public XPath parseXPath (String xpath) throws SAXPathException
 385  
     {
 386  14
         return new JDOMXPath(xpath);
 387  
     }
 388  
 
 389  
     public Object getDocumentNode(Object contextNode)
 390  
     {
 391  536
         if ( contextNode instanceof Document )
 392  
         {
 393  398
             return contextNode;
 394  
         }
 395  
 
 396  138
         Element elem = (Element) contextNode;
 397  
 
 398  138
         return elem.getDocument();
 399  
     }
 400  
 
 401  
     public String getElementQName(Object obj)
 402  
     {
 403  52
         Element elem = (Element) obj;
 404  
 
 405  52
         String prefix = elem.getNamespacePrefix();
 406  
 
 407  52
         if ( prefix == null || prefix.length() == 0 )
 408  
         {
 409  52
             return elem.getName();
 410  
         }
 411  
 
 412  0
         return prefix + ":" + elem.getName();
 413  
     }
 414  
 
 415  
     public String getAttributeQName(Object obj)
 416  
     {
 417  0
         Attribute attr = (Attribute) obj;
 418  
 
 419  0
         String prefix = attr.getNamespacePrefix();
 420  
 
 421  0
         if ( prefix == null || "".equals( prefix ) )
 422  
         {
 423  0
             return attr.getName();
 424  
         }
 425  
 
 426  0
         return prefix + ":" + attr.getName();
 427  
     }
 428  
 
 429  
     public String getNamespaceStringValue(Object obj)
 430  
     {
 431  0
         if (obj instanceof Namespace) {
 432  
 
 433  0
             Namespace ns = (Namespace) obj;
 434  0
             return ns.getURI();
 435  
         } else {
 436  
 
 437  0
             XPathNamespace ns = (XPathNamespace) obj;
 438  0
             return ns.getJDOMNamespace().getURI();
 439  
         }
 440  
         
 441  
     }
 442  
 
 443  
     public String getNamespacePrefix(Object obj)
 444  
     {
 445  234
         if (obj instanceof Namespace) {
 446  
 
 447  0
             Namespace ns = (Namespace) obj;
 448  0
             return ns.getPrefix();
 449  
         } else {
 450  
 
 451  234
             XPathNamespace ns = (XPathNamespace) obj;
 452  234
             return ns.getJDOMNamespace().getPrefix();
 453  
         }
 454  
     }
 455  
 
 456  
     public String getTextStringValue(Object obj)
 457  
     {
 458  28
         if ( obj instanceof Text )
 459  
         {
 460  28
             return ((Text)obj).getText();
 461  
         }
 462  
 
 463  0
         if ( obj instanceof CDATA )
 464  
         {
 465  0
             return ((CDATA)obj).getText();
 466  
         }
 467  
 
 468  0
         return "";
 469  
     }
 470  
 
 471  
     public String getAttributeStringValue(Object obj)
 472  
     {
 473  574
         Attribute attr = (Attribute) obj;
 474  
 
 475  574
         return attr.getValue();
 476  
     }
 477  
 
 478  
     public String getElementStringValue(Object obj)
 479  
     {
 480  276
         Element elem = (Element) obj;
 481  
 
 482  276
         StringBuffer buf = new StringBuffer();
 483  
 
 484  276
         List     content     = elem.getContent();
 485  276
         Iterator contentIter = content.iterator();
 486  276
         Object   each        = null;
 487  
 
 488  560
         while ( contentIter.hasNext() )
 489  
         {
 490  284
             each = contentIter.next();
 491  
 
 492  284
             if ( each instanceof Text )
 493  
             {
 494  266
                 buf.append( ((Text)each).getText() );
 495  266
             }
 496  18
             else if ( each instanceof CDATA )
 497  
             {
 498  0
                 buf.append( ((CDATA)each).getText() );
 499  0
             }
 500  18
             else if ( each instanceof Element )
 501  
             {
 502  18
                 buf.append( getElementStringValue( each ) );
 503  18
             }
 504  
         }
 505  
 
 506  276
         return buf.toString();
 507  
     }
 508  
 
 509  
     public String getProcessingInstructionTarget(Object obj)
 510  
     {
 511  12
         ProcessingInstruction pi = (ProcessingInstruction) obj;
 512  
 
 513  12
         return pi.getTarget();
 514  
     }
 515  
 
 516  
     public String getProcessingInstructionData(Object obj)
 517  
     {
 518  6
         ProcessingInstruction pi = (ProcessingInstruction) obj;
 519  
 
 520  6
         return pi.getData();
 521  
     }
 522  
 
 523  
     public String getCommentStringValue(Object obj)
 524  
     {
 525  0
         Comment cmt = (Comment) obj;
 526  
 
 527  0
         return cmt.getText();
 528  
     }
 529  
 
 530  
     public String translateNamespacePrefixToUri(String prefix, Object context)
 531  
     {
 532  0
         Element element = null;
 533  0
         if ( context instanceof Element ) 
 534  
         {
 535  0
             element = (Element) context;
 536  0
         }
 537  0
         else if ( context instanceof Text )
 538  
         {
 539  0
             element = (Element)((Text)context).getParent();
 540  0
         }
 541  0
         else if ( context instanceof Attribute )
 542  
         {
 543  0
             element = ((Attribute)context).getParent();
 544  0
         }
 545  0
         else if ( context instanceof XPathNamespace )
 546  
         {
 547  0
             element = ((XPathNamespace)context).getJDOMElement();
 548  0
         }
 549  0
         else if ( context instanceof Comment )
 550  
         {
 551  0
             element = (Element)((Comment)context).getParent();
 552  0
         }
 553  0
         else if ( context instanceof ProcessingInstruction )
 554  
         {
 555  0
             element = (Element)((ProcessingInstruction)context).getParent();
 556  
         }
 557  
 
 558  0
         if ( element != null )
 559  
         {
 560  0
             Namespace namespace = element.getNamespace( prefix );
 561  
 
 562  0
             if ( namespace != null ) 
 563  
             {
 564  0
                 return namespace.getURI();
 565  
             }
 566  
         }
 567  0
         return null;
 568  
     }
 569  
 
 570  
     public Object getDocument(String url) throws FunctionCallException
 571  
     {
 572  
         try
 573  
         {
 574  136
             SAXBuilder builder = new SAXBuilder();
 575  
             
 576  136
             return builder.build( url );
 577  
         }
 578  0
         catch (Exception e)
 579  
         {
 580  0
             throw new FunctionCallException( e.getMessage() );
 581  
         }
 582  
     }
 583  
 }