View Javadoc

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