View Javadoc

1   /*
2    * $Header: /home/projects/jaxen/scm/jaxen/src/java/main/org/jaxen/dom/NamespaceNode.java,v 1.9 2005/04/06 09:19:15 elharo Exp $
3    * $Revision: 1.9 $
4    * $Date: 2005/04/06 09:19:15 $
5    *
6    * ====================================================================
7    *
8    * Copyright (C) 2000-2002 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: NamespaceNode.java,v 1.9 2005/04/06 09:19:15 elharo Exp $
60   */
61  
62  ////////////////////////////////////////////////////////////////////
63  // Inner class for a Namespace node.
64  ////////////////////////////////////////////////////////////////////
65  
66  package org.jaxen.dom;
67  
68  import org.jaxen.pattern.Pattern;
69  import org.w3c.dom.DOMException;
70  import org.w3c.dom.Document;
71  import org.w3c.dom.NamedNodeMap;
72  import org.w3c.dom.Node;
73  import org.w3c.dom.NodeList;
74  
75  
76  /***
77   * Extension DOM2 node type for a namespace declaration.
78   *
79   * <p>This class implements the DOM2 {@link Node} interface to
80   * allow Namespace declarations to be included in the result
81   * set of an XPath selectNodes operation, even though DOM2 does
82   * not model Namespace declarations as separate nodes.</p>
83   *
84   * <p>While all of the methods are implemented with reasonable
85   * defaults, there will be some unexpected surprises, so users are
86   * advised to test for NamespaceNodes and filter them out from the
87   * result sets as early as possible:</p>
88   *
89   * <ol>
90   *
91   * <li>The {@link #getNodeType} method returns {@link #NAMESPACE_NODE},
92   * which is not one of the usual DOM2 node types.  Generic code may
93   * fall unexpectedly out of switch statements, for example.</li>
94   *
95   * <li>The {@link #getOwnerDocument} method returns the owner document
96   * of the parent node, but that owner document will know nothing about
97   * the Namespace node.</p>
98   *
99   * <li>The {@link #isSupported} method always returns false.</li>
100  *
101  * </ol>
102  *
103  * <p>All attempts to modify a NamespaceNode will fail with a {@link
104  * DOMException} ({@link
105  * DOMException#NO_MODIFICATION_ALLOWED_ERR}).</p>
106  *
107  * <p>This class has only protected constructors, so that it can be
108  * instantiated only by {@link DocumentNavigator}.</p>
109  *
110  * @author David Megginson
111  * @see DocumentNavigator
112  */
113 public class NamespaceNode implements Node
114 {
115 
116 
117     ////////////////////////////////////////////////////////////////////
118     // Constants.
119     ////////////////////////////////////////////////////////////////////
120 
121     /***
122      * Constant: this is a NamespaceNode.
123      *
124      * @see #getNodeType
125      */
126     public final static short NAMESPACE_NODE = Pattern.NAMESPACE_NODE;
127 
128 
129 
130     ////////////////////////////////////////////////////////////////////
131     // Protected Constructors.
132     ////////////////////////////////////////////////////////////////////
133 
134 
135     /***
136      * Constructor.
137      *
138      * @param parent the DOM node to which the namespace is attached
139      * @param name the namespace prefix
140      * @param value the namespace URI
141      */
142     public NamespaceNode (Node parent, String name, String value)
143     {
144         this.parent = parent;
145         this.name = name;
146         this.value = value;
147     }
148 
149 
150     /***
151      * Constructor.
152      *
153      * @param parent the DOM node to which the namespace is attached
154      * @param attribute the DOM attribute object containing the
155      *        namespace declaration
156      */
157     NamespaceNode (Node parent, Node attribute)
158     {
159         String name = attribute.getNodeName();
160     
161         if (name.equals("xmlns")) {
162             this.name = "";
163         }
164         else {
165             this.name = name.substring(6); // the part after "xmlns:"
166         }
167         this.parent = parent;
168         this.value = attribute.getNodeValue();
169     }
170 
171 
172 
173     ////////////////////////////////////////////////////////////////////
174     // Implementation of org.w3c.dom.Node.
175     ////////////////////////////////////////////////////////////////////
176 
177 
178     /***
179      * Get the namespace prefix.
180      *
181      * @return the namespace prefix, or "" for the default namespace
182      */
183     public String getNodeName ()
184     {
185         return name;
186     }
187 
188 
189     /***
190      * Get the namespace URI.
191      *
192      * @return the Namespace URI
193      */
194     public String getNodeValue ()
195     {
196         return value;
197     }
198 
199 
200     /***
201      * Change the Namespace URI (always fails).
202      *
203      * @param value the new URI
204      * @throws DOMException always thrown
205      */
206     public void setNodeValue (String value) throws DOMException
207     {
208         disallowModification();
209     }
210 
211 
212     /***
213      * Get the node type.
214      *
215      * @return Always {@link #NAMESPACE_NODE}.
216      */
217     public short getNodeType ()
218     {
219         return NAMESPACE_NODE;
220     }
221 
222 
223     /***
224      * Get the parent node.
225      *
226      * <p>This method returns the element that was queried for Namespaces
227      * in effect, <em>not</em> necessarily the actual element containing
228      * the Namespace declaration.</p>
229      *
230      * @return the parent node (not null)
231      */
232     public Node getParentNode ()
233     {
234         return parent;
235     }
236 
237 
238     /***
239      * Get the list of child nodes.
240      *
241      * @return an empty node list
242      */
243     public NodeList getChildNodes ()
244     {
245         return new EmptyNodeList();
246     }
247 
248 
249     /***
250      * Get the first child node.
251      *
252      * @return null
253      */
254     public Node getFirstChild ()
255     {
256         return null;
257     }
258 
259 
260     /***
261      * Get the last child node.
262      *
263      * @return null
264      */
265     public Node getLastChild ()
266     {
267         return null;
268     }
269 
270 
271     /***
272      * Get the previous sibling node.
273      *
274      * @return null
275      */
276     public Node getPreviousSibling ()
277     {
278         return null;
279     }
280 
281 
282     /***
283      * Get the next sibling node.
284      *
285      * @return null
286      */
287     public Node getNextSibling ()
288     {
289         return null;
290     }
291 
292 
293     /***
294      * Get the attribute nodes.
295      *
296      * @return null
297      */
298     public NamedNodeMap getAttributes ()
299     {
300         return null;
301     }
302 
303 
304     /***
305      * Get the owner document.
306      *
307      * @return the owner document <em>of the parent node</em>
308      */
309     public Document getOwnerDocument ()
310     {
311                     // FIXME: this could cause confusion
312         return (parent == null ? null : parent.getOwnerDocument());
313     }
314 
315 
316     /***
317      * Insert a new child node (always fails).
318      *
319      * @throws DOMException always thrown
320      * @see Node#insertBefore
321      */
322     public Node insertBefore (Node newChild, Node refChild)
323     throws DOMException
324     {
325         disallowModification();
326         return null;
327     }
328 
329 
330     /***
331      * Replace a child node (always fails).
332      *
333      * @throws DOMException always thrown
334      * @see Node#replaceChild
335      */
336     public Node replaceChild (Node newChild, Node oldChild)
337     throws DOMException
338     {
339         disallowModification();
340         return null;
341     }
342 
343 
344     /***
345      * Remove a child node (always fails).
346      *
347      * @throws DOMException always thrown
348      * @see Node#removeChild
349      */
350     public Node removeChild (Node oldChild)
351     throws DOMException
352     {
353         disallowModification();
354         return null;
355     }
356 
357 
358     /***
359      * Append a new child node (always fails).
360      *
361      * @throws DOMException always thrown
362      * @see Node#appendChild
363      */
364     public Node appendChild (Node newChild)
365     throws DOMException
366     {
367         disallowModification();
368         return null;
369     }
370 
371 
372     /***
373      * Test for child nodes.
374      *
375      * @return false
376      */
377     public boolean hasChildNodes ()
378     {
379         return false;
380     }
381 
382 
383     /***
384      * Create a copy of this node.
385      *
386      * @param deep Make a deep copy (no effect, since Namespace nodes
387      *        don't have children).
388      * @return a new copy of this Namespace node
389      */
390     public Node cloneNode (boolean deep)
391     {
392         return new NamespaceNode(parent, name, value);
393     }
394 
395 
396     /***
397      * Normalize the text descendants of this node.
398      *
399      * <p>This method has no effect, since Namespace nodes have no
400      * descendants.</p>
401      */
402     public void normalize ()
403     {
404     // no op
405     }
406 
407 
408     /***
409      * Test if a DOM2 feature is supported.
410      *
411      * @param feature the feature name
412      * @param version the feature version
413      * @return false
414      */
415     public boolean isSupported (String feature, String version)
416     {
417         return false;
418     }
419 
420 
421     /***
422      * Get the Namespace URI for this node.
423      *
424      * <p>Namespace declarations are not themselves
425      * Namespace-qualified.</p>
426      *
427      * @return null
428      */
429     public String getNamespaceURI ()
430     {
431        return null;
432     }
433 
434 
435     /***
436      * Get the namespace prefix for this node.
437      *
438      * <p>Namespace declarations are not themselves
439      * Namespace-qualified.</p>
440      *
441      * @return null
442      */
443     public String getPrefix ()
444     {
445         return null;
446     }
447 
448 
449     /***
450      * Change the Namespace prefix for this node (always fails).
451      *
452      * @param prefix the new prefix
453      * @throws DOMException always thrown
454      */
455     public void setPrefix (String prefix)
456     throws DOMException
457     {
458         disallowModification();
459     }
460 
461 
462     /***
463      * Get the local name for this node.
464      *
465      * @return null
466      */
467     public String getLocalName ()
468     {
469         return name;
470     }
471 
472 
473     /***
474      * Test if this node has attributes.
475      *
476      * @return false
477      */
478     public boolean hasAttributes ()
479     {
480         return false;
481     }
482 
483 
484     /***
485      * Throw a NO_MODIFICATION_ALLOWED_ERR DOMException.
486      *
487      * @throws DOMException always thrown
488      */
489     private void disallowModification () throws DOMException
490     {
491         throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
492                    "Namespace node may not be modified");
493     }
494 
495 
496 
497     ////////////////////////////////////////////////////////////////////
498     // Override default methods from java.lang.Object.
499     ////////////////////////////////////////////////////////////////////
500 
501 
502     /***
503      * Generate a hash code for a Namespace node.
504      *
505      * <p>The hash code is the sum of the hash codes of the parent node,
506      * name, and value.</p>
507      *
508      * @return a hash code for this node
509      */
510     public int hashCode ()
511     {
512     return hashCode(parent) + hashCode(name) + hashCode(value);
513     }
514 
515 
516     /***
517      * Test for equivalence with another object.
518      *
519      * <p>Two Namespace nodes are considered equivalent if their parents,
520      * names, and values are equal.</p>
521      *
522      * @param o The object to test for equality.
523      * @return true if the object is equivalent to this node, false
524      *         otherwise.
525      */
526     public boolean equals (Object o)
527     {
528         if (o == this) return true;
529         else if (o == null) return false;
530         else if (o instanceof NamespaceNode) {
531             NamespaceNode ns = (NamespaceNode)o;
532             return (equals(parent, ns.getParentNode()) &&
533                 equals(name, ns.getNodeName()) &&
534                 equals(value, ns.getNodeValue()));
535         } else {
536             return false;
537         }
538     }
539 
540 
541     /***
542      * Helper method for generating a hash code.
543      *
544      * @param o the object for generating a hash code (possibly null)
545      * @return the object's hash code, or 0 if the object is null
546      * @see java.lang.Object#hashCode
547      */
548     private int hashCode (Object o)
549     {
550     return (o == null ? 0 : o.hashCode());
551     }
552 
553 
554     /***
555      * Helper method for comparing two objects.
556      *
557      * @param a the first object to compare (possibly null)
558      * @param b the second object to compare (possibly null)
559      * @return true if the objects are equivalent or are both null
560      * @see java.lang.Object#equals
561      */
562     private boolean equals (Object a, Object b)
563     {
564         return ((a == null && b == null) ||
565           (a != null && a.equals(b)));
566     }
567 
568 
569     ////////////////////////////////////////////////////////////////////
570     // Internal state.
571     ////////////////////////////////////////////////////////////////////
572 
573     private Node parent;
574     private String name;
575     private String value;
576 
577 
578 
579     ////////////////////////////////////////////////////////////////////
580     // Inner class: empty node list.
581     ////////////////////////////////////////////////////////////////////
582 
583 
584     /***
585      * A node list with no members.
586      *
587      * <p>This class is necessary for the {@link Node#getChildNodes}
588      * method, which must return an empty node list rather than
589      * null when there are no children.</p>
590      */
591     class EmptyNodeList implements NodeList
592     {
593 
594     /***
595      * @see NodeList#getLength
596      */
597     public int getLength ()
598     {
599         return 0;
600     }
601 
602 
603     /***
604      * @see NodeList#item
605      */
606     public Node item(int index)
607     {
608         return null;
609     }
610     
611     }
612 }
613 
614 // end of Namespace.java