View Javadoc

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