View Javadoc

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