View Javadoc
1   /*
2    * $Header$
3    * $Revision$
4    * $Date$
5    *
6    * ====================================================================
7    *
8    * Copyright 2000-2003 bob mcwhirter & James Strachan.
9    * All rights reserved.
10   *
11   *
12   * Redistribution and use in source and binary forms, with or without
13   * modification, are permitted provided that the following conditions are
14   * met:
15   * 
16   *   * Redistributions of source code must retain the above copyright
17   *     notice, this list of conditions and the following disclaimer.
18   * 
19   *   * Redistributions in binary form must reproduce the above copyright
20   *     notice, this list of conditions and the following disclaimer in the
21   *     documentation and/or other materials provided with the distribution.
22   * 
23   *   * Neither the name of the Jaxen Project nor the names of its
24   *     contributors may be used to endorse or promote products derived 
25   *     from this software without specific prior written permission.
26   * 
27   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
28   * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29   * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
30   * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
31   * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
32   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
33   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
34   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
35   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
36   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38   *
39   * ====================================================================
40   * This software consists of voluntary contributions made by many
41   * individuals on behalf of the Jaxen Project and was originally
42   * created by bob mcwhirter <bob@werken.com> and
43   * James Strachan <jstrachan@apache.org>.  For more information on the
44   * Jaxen Project, please see <http://www.jaxen.org/>.
45   *
46   * $Id$
47   */
48  
49  
50  package org.jaxen.xom;
51  
52  
53  import nu.xom.Attribute;
54  import nu.xom.Comment;
55  import nu.xom.Document;
56  import nu.xom.Element;
57  import nu.xom.ProcessingInstruction;
58  import nu.xom.Text;
59  import nu.xom.Node;
60  import nu.xom.Builder;
61  import nu.xom.NodeFactory;
62  import nu.xom.ParentNode;
63  
64  import org.jaxen.XPath;
65  import org.jaxen.UnsupportedAxisException;
66  import org.jaxen.FunctionCallException;
67  import org.jaxen.BaseXPath;
68  import org.jaxen.JaxenConstants;
69  import org.jaxen.util.SingleObjectIterator;
70  
71  import org.jaxen.saxpath.SAXPathException;
72  
73  import java.util.Iterator;
74  import java.util.HashMap;
75  import java.util.Map;
76  
77  /**
78   * Interface for navigating around the XOM object model.
79   *
80   * <p>
81   * This class is not intended for direct usage, but is
82   * used by the Jaxen engine during evaluation.
83   * </p>
84   *
85   * @see XPath
86   *
87   */
88  public class DocumentNavigator extends org.jaxen.DefaultNavigator
89  {
90      /**
91       * 
92       */
93      private static final long serialVersionUID = 3159311338575942877L;
94  
95      public boolean isAttribute(Object o) {
96          return o instanceof Attribute;
97      }
98  
99      public boolean isComment(Object o) {
100         return o instanceof Comment;
101     }
102 
103     public boolean isDocument(Object o) {
104         return o instanceof Document;
105     }
106 
107     public boolean isElement(Object o) {
108         return o instanceof Element;
109     }
110 
111     public boolean isNamespace(Object o) {
112         return o instanceof XPathNamespace;
113     }
114 
115     public boolean isProcessingInstruction(Object o) {
116         return o instanceof ProcessingInstruction;
117     }
118 
119     public boolean isText(Object o) {
120         return o instanceof Text;
121     }
122 
123     //
124     
125     public String getAttributeName(Object o) {
126         return (isAttribute(o) ? ((Attribute)o).getLocalName() : null);
127     }
128 
129     public String getAttributeNamespaceUri(Object o) {
130         return (isAttribute(o) ? ((Attribute)o).getNamespaceURI() : null);
131     }
132 
133     public String getAttributeQName(Object o) {
134         return (isAttribute(o) ? ((Attribute)o).getQualifiedName() : null);
135     }
136 
137     public String getAttributeStringValue(Object o) {
138         return (isAttribute(o) ? ((Attribute)o).getValue() : null);
139     }
140 
141     //
142     
143     public String getCommentStringValue(Object o) {
144         return (isComment(o) ? ((Comment)o).getValue() : null);
145     }
146 
147     public String getElementName(Object o) {
148         return (isElement(o) ? ((Element)o).getLocalName() : null);
149     }
150 
151     public String getElementNamespaceUri(Object o) {
152         return (isElement(o) ? ((Element)o).getNamespaceURI() : null);
153     }
154 
155     public String getElementQName(Object o) {
156         return (isElement(o) ? ((Element)o).getQualifiedName() : null);
157     }
158 
159     public String getElementStringValue(Object o) {
160         return (o instanceof Node ? ((Node)o).getValue() : null);
161     }
162 
163     //
164     
165     public String getNamespacePrefix(Object o) {
166         if (isElement(o)) {
167             return ((Element)o).getNamespacePrefix();
168         } else if (isAttribute(o)) {
169             return ((Attribute)o).getNamespacePrefix();
170         } else if (o instanceof XPathNamespace) {
171             return ((XPathNamespace)o).getNamespacePrefix();
172         }
173         return null;
174     }
175 
176     public String getNamespaceStringValue(Object o) {
177         if (isElement(o)) {
178             return ((Element)o).getNamespaceURI();
179         } else if (isAttribute(o)) {
180             return ((Attribute)o).getNamespaceURI();
181         } else if (o instanceof XPathNamespace) {
182             return ((XPathNamespace)o).getNamespaceURI();
183         }
184         return null;
185     }
186 
187     //
188     
189     public String getTextStringValue(Object o) {
190         return (o instanceof Text ? ((Text)o).getValue() : null);
191     }
192     
193     //
194 
195     public Object getDocument(String s) throws FunctionCallException {
196         try {
197             return new Builder(new NodeFactory()).build(s);
198         } catch (Exception pe) {
199             throw new FunctionCallException(pe);
200         }
201     }
202 
203     public Object getDocumentNode(Object o) {
204         ParentNode parent = null;
205         if (o instanceof ParentNode) {
206             parent = (ParentNode)o;
207         } else if (o instanceof Node) {
208             parent = ((Node)o).getParent();
209         }
210         return parent.getDocument();
211     }
212 
213     //
214     
215     private abstract static class IndexIterator implements Iterator {
216         private Object o = null;
217         private int pos = 0, end = -1;
218         public IndexIterator(Object o, int pos, int end) {
219             this.o = o;
220             this.pos = pos;
221             this.end = end;
222         }
223         public boolean hasNext() {
224             return pos < end;
225         }
226         public abstract Object get(Object o, int i); 
227         
228         public Object next() {
229             return get(o, pos++);
230         }
231 
232         public void remove() {
233             throw new UnsupportedOperationException();
234         }
235     }
236     
237     //
238     
239     public Iterator getAttributeAxisIterator(Object o) {
240         if (isElement(o)) {
241             return new IndexIterator(o, 0, ((Element)o).getAttributeCount()) {
242                 public Object get(Object o, int i) {
243                     return ((Element)o).getAttribute(i);
244                 }
245             };
246         }
247         return JaxenConstants.EMPTY_ITERATOR;
248     }
249 
250     public Iterator getChildAxisIterator(Object o) {
251         if (isElement(o) || (o instanceof Document)) {
252             return new IndexIterator(o, 0, ((ParentNode)o).getChildCount()) {
253                 public Object get(Object o, int i) {
254                     return ((ParentNode)o).getChild(i);
255                 }
256             };
257         }
258         return JaxenConstants.EMPTY_ITERATOR;
259     }
260 
261     //
262 
263     public Iterator getParentAxisIterator(Object o) {
264         Object parent = null;
265         if (o instanceof Node) {
266             parent = ((Node)o).getParent();
267         } else if (isNamespace(o)) {
268             parent = ((XPathNamespace)o).getElement();
269         }
270         return (parent != null ? new SingleObjectIterator(parent) : null);
271     }
272 
273     public Object getParentNode(Object o)  {
274         return (o instanceof Node ? ((Node)o).getParent() : null);
275     }
276 
277     //
278 
279     public Iterator getPrecedingAxisIterator(Object o) throws UnsupportedAxisException {
280         return super.getPrecedingAxisIterator(o);
281     }
282 
283     public Iterator getPrecedingSiblingAxisIterator(Object o) throws UnsupportedAxisException {
284         return super.getPrecedingSiblingAxisIterator(o);
285     }
286     
287     //
288 
289     public String getProcessingInstructionData(Object o) {
290         return (o instanceof ProcessingInstruction ? ((ProcessingInstruction)o).getValue() : null);
291     }
292 
293     public String getProcessingInstructionTarget(Object o) {
294         return (o instanceof ProcessingInstruction ? ((ProcessingInstruction)o).getTarget() : null);
295     }
296 
297     //
298 
299     public String translateNamespacePrefixToUri(String s, Object o) {
300         Element element = null;
301         if (o instanceof Element) {
302             element = (Element) o;
303         } else if (o instanceof ParentNode) {
304         }
305         else if (o instanceof Node) {
306             element = (Element)((Node)o).getParent();
307         }
308         else if (o instanceof XPathNamespace)
309         {
310             element = ((XPathNamespace)o).getElement();
311         }
312         if (element != null) {
313             return element.getNamespaceURI(s);
314         }
315         return null;
316     }
317 
318     //
319     
320     public XPath parseXPath(String s) throws SAXPathException {
321         return new BaseXPath(s, this);
322     }
323 
324     //
325     
326     /** Wrapper for XOM namespace nodes to give them a parent,
327      * as required by the XPath data model.
328      *
329      *  @author Erwin Bolwidt
330      */
331     private static class XPathNamespace
332     {
333         private Element element;
334 
335         private String uri, prefix;
336 
337         public XPathNamespace(Element elt, String uri, String prefix)
338         {
339             element = elt;
340             this.uri = uri;
341             this.prefix = prefix;
342         }
343 
344         /** Returns the XOM element from which this namespace node has been 
345          *  retrieved. The result may be null when the namespace node has not yet
346          *  been assigned to an element.
347          */
348         public Element getElement()
349         {
350             return element;
351         }
352 
353         public String getNamespaceURI()
354         {
355             return uri;
356         }
357 
358         public String getNamespacePrefix()
359         {
360             return prefix;
361         }
362 
363         public String toString()
364         {
365             return ( "[xmlns:" + prefix + "=\"" +
366                     uri + "\", element=" +
367                     element.getLocalName() + "]" );
368         }
369     }
370 
371     //
372     
373     private boolean addNamespaceForElement(Element elt, String uri, String prefix, Map map)
374     {
375         if (uri != null && uri.length() > 0 && (! map.containsKey(prefix))) {
376             map.put(prefix, new XPathNamespace(elt, uri, prefix));
377             return true;
378         }
379         return false;
380     }
381     
382     public Iterator getNamespaceAxisIterator(Object o)
383     {
384         if (! isElement(o)) {
385             return JaxenConstants.EMPTY_ITERATOR;
386         }
387         Map nsMap = new HashMap();
388         Element elt = (Element)o;
389         ParentNode parent = elt;
390         
391         while (parent instanceof Element) {
392             elt = (Element)parent;
393             String uri    = elt.getNamespaceURI();
394             String prefix = elt.getNamespacePrefix();
395             addNamespaceForElement(elt, uri, prefix, nsMap);
396             int count = elt.getNamespaceDeclarationCount();
397             for (int i = 0; i < count; i++) {
398                 prefix = elt.getNamespacePrefix(i);
399                 uri    = elt.getNamespaceURI(prefix);
400                 addNamespaceForElement(elt, uri, prefix, nsMap);
401             }
402             parent = elt.getParent();
403         }
404         addNamespaceForElement(elt, "http://www.w3.org/XML/1998/namespace", "xml", nsMap);
405 
406         return nsMap.values().iterator();
407     }
408 }