Coverage Report - org.jaxen.dom.NamespaceNode
 
Classes in this File Line Coverage Branch Coverage Complexity
NamespaceNode
35%
45/130
52%
12/23
1.935
NamespaceNode$1
N/A
N/A
1.935
NamespaceNode$EmptyNodeList
0%
0/3
N/A
1.935
 
 1  
 /*
 2  
  * $Header: /home/projects/jaxen/scm/jaxen/src/java/main/org/jaxen/dom/NamespaceNode.java,v 1.25 2006/07/03 11:14:05 elharo Exp $
 3  
  * $Revision: 1.25 $
 4  
  * $Date: 2006/07/03 11:14:05 $
 5  
  *
 6  
  * ====================================================================
 7  
  *
 8  
  * Copyright 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 are
 13  
  * met:
 14  
  * 
 15  
  *   * Redistributions of source code must retain the above copyright
 16  
  *     notice, this list of conditions and the following disclaimer.
 17  
  * 
 18  
  *   * Redistributions in binary form must reproduce the above copyright
 19  
  *     notice, this list of conditions and the following disclaimer in the
 20  
  *     documentation and/or other materials provided with the distribution.
 21  
  * 
 22  
  *   * Neither the name of the Jaxen Project nor the names of its
 23  
  *     contributors may be used to endorse or promote products derived 
 24  
  *     from this software without specific prior written permission.
 25  
  * 
 26  
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 27  
  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 28  
  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 29  
  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 30  
  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 31  
  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 32  
  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 33  
  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 34  
  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 35  
  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 36  
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 37  
  *
 38  
  * ====================================================================
 39  
  * This software consists of voluntary contributions made by many 
 40  
  * individuals on behalf of the Jaxen Project and was originally 
 41  
  * created by bob mcwhirter <bob@werken.com> and 
 42  
  * James Strachan <jstrachan@apache.org>.  For more information on the 
 43  
  * Jaxen Project, please see <http://www.jaxen.org/>.
 44  
  * 
 45  
  * $Id: NamespaceNode.java,v 1.25 2006/07/03 11:14:05 elharo Exp $
 46  
  */
 47  
 
 48  
 ////////////////////////////////////////////////////////////////////
 49  
 // Inner class for a Namespace node.
 50  
 ////////////////////////////////////////////////////////////////////
 51  
 
 52  
 package org.jaxen.dom;
 53  
 
 54  
 import java.lang.reflect.InvocationTargetException;
 55  
 import java.lang.reflect.Method;
 56  
 import java.util.HashMap;
 57  
 
 58  
 import org.jaxen.pattern.Pattern;
 59  
 import org.w3c.dom.DOMException;
 60  
 import org.w3c.dom.Document;
 61  
 import org.w3c.dom.NamedNodeMap;
 62  
 import org.w3c.dom.Node;
 63  
 import org.w3c.dom.NodeList;
 64  
 import org.w3c.dom.UserDataHandler;
 65  
 
 66  
 
 67  
 /**
 68  
  * Extension DOM2/DOM3 node type for a namespace node.
 69  
  *
 70  
  * <p>This class implements the DOM2 and DOM3 {@link Node} interface
 71  
  * to allow namespace nodes to be included in the result
 72  
  * set of an XPath selectNodes operation, even though DOM does
 73  
  * not model namespaces in scope as separate nodes.</p>
 74  
  *
 75  
  * <p>
 76  
  * While all of the DOM2 methods are implemented with reasonable
 77  
  * defaults, there will be some unexpected surprises, so users are
 78  
  * advised to test for NamespaceNodes and filter them out from the
 79  
  * result sets as early as possible.
 80  
   * </p>
 81  
  *
 82  
  * <ol>
 83  
  *
 84  
  * <li>The {@link #getNodeType} method returns {@link #NAMESPACE_NODE},
 85  
  * which is not one of the usual DOM2 node types.  Generic code may
 86  
  * fall unexpectedly out of switch statements, for example.</li>
 87  
  *
 88  
  * <li>The {@link #getOwnerDocument} method returns the owner document
 89  
  * of the parent node, but that owner document will know nothing about
 90  
  * the namespace node.</p>
 91  
  *
 92  
  * <li>The {@link #isSupported} method always returns false.</li>
 93  
  *
 94  
  * <li> The DOM3 methods sometimes throw UnsupportedOperationException.
 95  
  *      They're here only to allow this class to be compiled with Java 1.5.
 96  
  *       Do not call or rely on them.</li>
 97  
  * </ol>
 98  
  *
 99  
  * <p>All attempts to modify a <code>NamespaceNode</code> will fail with a {@link
 100  
  * DOMException} ({@link
 101  
  * DOMException#NO_MODIFICATION_ALLOWED_ERR}).</p>
 102  
  *
 103  
  * @author David Megginson
 104  
  * @author Elliotte Rusty Harold
 105  
  * @see DocumentNavigator
 106  
  */
 107  
 public class NamespaceNode implements Node
 108  
 {
 109  
 
 110  
     /**
 111  
      * Constant: this is a NamespaceNode.
 112  
      *
 113  
      * @see #getNodeType
 114  
      */
 115  
     public final static short NAMESPACE_NODE = Pattern.NAMESPACE_NODE;
 116  
 
 117  
     // FIXME "Note: Numeric codes up to 200 are reserved to W3C for possible future use."
 118  
     // We should be using higher codes. Here we're using 13, the same as DOM 3's type for XPathNamespace.
 119  
     // However, that's only a note not a recommendation.
 120  
 
 121  
     /**
 122  
      * Create a new NamespaceNode.
 123  
      *
 124  
      * @param parent the DOM node to which the namespace is attached
 125  
      * @param name the namespace prefix
 126  
      * @param value the namespace URI
 127  
      */
 128  
     public NamespaceNode (Node parent, String name, String value)
 129  284
     {
 130  284
         this.parent = parent;
 131  284
         this.name = name;
 132  284
         this.value = value;
 133  284
     }
 134  
 
 135  
 
 136  
     /**
 137  
      * Constructor.
 138  
      *
 139  
      * @param parent the DOM node to which the namespace is attached
 140  
      * @param attribute the DOM attribute object containing the
 141  
      *        namespace declaration
 142  
      */
 143  
     NamespaceNode (Node parent, Node attribute)
 144  202
     {
 145  202
         String attributeName = attribute.getNodeName();
 146  
     
 147  202
         if (attributeName.equals("xmlns")) {
 148  0
             this.name = "";
 149  0
         }
 150  202
         else if (attributeName.startsWith("xmlns:")) {
 151  202
             this.name = attributeName.substring(6); // the part after "xmlns:"
 152  202
         }
 153  
         else { // workaround for Crimson bug; Crimson incorrectly reports the prefix as the node name
 154  0
             this.name = attributeName;
 155  
         }
 156  202
         this.parent = parent;
 157  202
         this.value = attribute.getNodeValue();
 158  202
     }
 159  
 
 160  
 
 161  
 
 162  
     ////////////////////////////////////////////////////////////////////
 163  
     // Implementation of org.w3c.dom.Node.
 164  
     ////////////////////////////////////////////////////////////////////
 165  
 
 166  
 
 167  
     /**
 168  
      * Get the namespace prefix.
 169  
      *
 170  
      * @return the namespace prefix, or "" for the default namespace
 171  
      */
 172  
     public String getNodeName ()
 173  
     {
 174  210
         return name;
 175  
     }
 176  
 
 177  
 
 178  
     /**
 179  
      * Get the namespace URI.
 180  
      *
 181  
      * @return the namespace URI
 182  
      */
 183  
     public String getNodeValue ()
 184  
     {
 185  28
         return value;
 186  
     }
 187  
 
 188  
 
 189  
     /**
 190  
      * Change the namespace URI (always fails).
 191  
      *
 192  
      * @param value the new URI
 193  
      * @throws DOMException always
 194  
      */
 195  
     public void setNodeValue (String value) throws DOMException
 196  
     {
 197  0
         disallowModification();
 198  0
     }
 199  
 
 200  
 
 201  
     /**
 202  
      * Get the node type.
 203  
      *
 204  
      * @return always {@link #NAMESPACE_NODE}.
 205  
      */
 206  
     public short getNodeType ()
 207  
     {
 208  3222
         return NAMESPACE_NODE;
 209  
     }
 210  
 
 211  
 
 212  
     /**
 213  
      * Get the parent node.
 214  
      *
 215  
      * <p>This method returns the element that was queried for Namespaces
 216  
      * in effect, <em>not</em> necessarily the actual element containing
 217  
      * the Namespace declaration.</p>
 218  
      *
 219  
      * @return the parent node (not null)
 220  
      */
 221  
     public Node getParentNode ()
 222  
     {
 223  786
         return parent;
 224  
     }
 225  
 
 226  
 
 227  
     /**
 228  
      * Get the list of child nodes.
 229  
      *
 230  
      * @return an empty node list
 231  
      */
 232  
     public NodeList getChildNodes ()
 233  
     {
 234  0
         return new EmptyNodeList();
 235  
     }
 236  
 
 237  
 
 238  
     /**
 239  
      * Get the first child node.
 240  
      *
 241  
      * @return null
 242  
      */
 243  
     public Node getFirstChild ()
 244  
     {
 245  0
         return null;
 246  
     }
 247  
 
 248  
 
 249  
     /**
 250  
      * Get the last child node.
 251  
      *
 252  
      * @return null
 253  
      */
 254  
     public Node getLastChild ()
 255  
     {
 256  0
         return null;
 257  
     }
 258  
 
 259  
 
 260  
     /**
 261  
      * Get the previous sibling node.
 262  
      *
 263  
      * @return null
 264  
      */
 265  
     public Node getPreviousSibling ()
 266  
     {
 267  0
         return null;
 268  
     }
 269  
 
 270  
 
 271  
     /**
 272  
      * Get the next sibling node.
 273  
      *
 274  
      * @return null
 275  
      */
 276  
     public Node getNextSibling ()
 277  
     {
 278  0
         return null;
 279  
     }
 280  
 
 281  
 
 282  
     /**
 283  
      * Get the attribute nodes.
 284  
      *
 285  
      * @return null
 286  
      */
 287  
     public NamedNodeMap getAttributes ()
 288  
     {
 289  0
         return null;
 290  
     }
 291  
 
 292  
 
 293  
     /**
 294  
      * Get the owner document.
 295  
      *
 296  
      * @return the owner document <em>of the parent node</em>
 297  
      */
 298  
     public Document getOwnerDocument ()
 299  
     {
 300  0
         if (parent == null) return null;
 301  0
         return parent.getOwnerDocument();
 302  
     }
 303  
 
 304  
 
 305  
     /**
 306  
      * Insert a new child node (always fails).
 307  
      * 
 308  
      * @param newChild the node to add
 309  
      * @param refChild ignored
 310  
      * @return never
 311  
      * @throws DOMException always
 312  
      * @see Node#insertBefore
 313  
      */
 314  
     public Node insertBefore (Node newChild, Node refChild)
 315  
     throws DOMException
 316  
     {
 317  0
         disallowModification();
 318  0
         return null;
 319  
     }
 320  
 
 321  
 
 322  
     /**
 323  
      * Replace a child node (always fails).
 324  
      *
 325  
      * @param newChild the node to add
 326  
      * @param oldChild the child node to replace
 327  
      * @return never
 328  
      * @throws DOMException always
 329  
      * @see Node#replaceChild
 330  
      */
 331  
     public Node replaceChild (Node newChild, Node oldChild) throws DOMException
 332  
     {
 333  0
         disallowModification();
 334  0
         return null;
 335  
     }
 336  
 
 337  
 
 338  
     /**
 339  
      * Remove a child node (always fails).
 340  
      *
 341  
      * @param oldChild the child node to remove
 342  
      * @return never
 343  
      * @throws DOMException always
 344  
      * @see Node#removeChild
 345  
      */
 346  
     public Node removeChild(Node oldChild) throws DOMException
 347  
     {
 348  0
         disallowModification();
 349  0
         return null;
 350  
     }
 351  
 
 352  
 
 353  
     /**
 354  
      * Append a new child node (always fails).
 355  
      *
 356  
      * @param newChild the node to add
 357  
      * @return never
 358  
      * @throws DOMException always
 359  
      * @see Node#appendChild
 360  
      */
 361  
     public Node appendChild(Node newChild) throws DOMException
 362  
     {
 363  0
         disallowModification();
 364  0
         return null;
 365  
     }
 366  
 
 367  
 
 368  
     /**
 369  
      * Test for child nodes.
 370  
      *
 371  
      * @return false
 372  
      */
 373  
     public boolean hasChildNodes()
 374  
     {
 375  0
         return false;
 376  
     }
 377  
 
 378  
 
 379  
     /**
 380  
      * Create a copy of this node.
 381  
      *
 382  
      * @param deep make a deep copy (no effect, since namespace nodes
 383  
      *        don't have children).
 384  
      * @return a new copy of this namespace node
 385  
      */
 386  
     public Node cloneNode (boolean deep)
 387  
     {
 388  0
         return new NamespaceNode(parent, name, value);
 389  
     }
 390  
 
 391  
 
 392  
     /**
 393  
      * Normalize the text descendants of this node.
 394  
      *
 395  
      * <p>This method has no effect, since namespace nodes have no
 396  
      * descendants.</p>
 397  
      */
 398  
     public void normalize ()
 399  
     {
 400  
     // no op
 401  0
     }
 402  
 
 403  
 
 404  
     /**
 405  
      * Test if a DOM2 feature is supported. (None are.)
 406  
      *
 407  
      * @param feature the feature name
 408  
      * @param version the feature version
 409  
      * @return false
 410  
      */
 411  
     public boolean isSupported(String feature, String version)
 412  
     {
 413  0
         return false;
 414  
     }
 415  
 
 416  
 
 417  
     /**
 418  
      * Get the namespace URI of this node.
 419  
      *
 420  
      * <p>Namespace declarations are not themselves
 421  
      * Namespace-qualified.</p>
 422  
      *
 423  
      * @return null
 424  
      */
 425  
     public String getNamespaceURI()
 426  
     {
 427  0
        return null;
 428  
     }
 429  
 
 430  
 
 431  
     /**
 432  
      * Get the namespace prefix of this node.
 433  
      *
 434  
      * <p>Namespace declarations are not themselves
 435  
      * namespace-qualified.</p>
 436  
      *
 437  
      * @return null
 438  
      * @see #getLocalName
 439  
      */
 440  
     public String getPrefix()
 441  
     {
 442  0
         return null;
 443  
     }
 444  
 
 445  
 
 446  
     /**
 447  
      * Change the namespace prefix of this node (always fails).
 448  
      *
 449  
      * @param prefix the new prefix
 450  
      * @throws DOMException always thrown
 451  
      */
 452  
     public void setPrefix(String prefix)
 453  
     throws DOMException
 454  
     {
 455  0
         disallowModification();
 456  0
     }
 457  
 
 458  
 
 459  
     /**
 460  
      * Get the XPath name of the namespace node;; i.e. the
 461  
      * namespace prefix.
 462  
      *
 463  
      * @return the namespace prefix
 464  
      */
 465  
     public String getLocalName ()
 466  
     {
 467  328
         return name;
 468  
     }
 469  
 
 470  
 
 471  
     /**
 472  
      * Test if this node has attributes.
 473  
      *
 474  
      * @return false
 475  
      */
 476  
     public boolean hasAttributes ()
 477  
     {
 478  0
         return false;
 479  
     }
 480  
 
 481  
 
 482  
     /**
 483  
      * Throw a NO_MODIFICATION_ALLOWED_ERR DOMException.
 484  
      *
 485  
      * @throws DOMException always thrown
 486  
      */
 487  
     private void disallowModification () throws DOMException
 488  
     {
 489  2
         throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
 490  
                    "Namespace node may not be modified");
 491  
     }
 492  
 
 493  
 
 494  
 
 495  
     ////////////////////////////////////////////////////////////////////
 496  
     // Override default methods from java.lang.Object.
 497  
     ////////////////////////////////////////////////////////////////////
 498  
 
 499  
 
 500  
     /**
 501  
      * Generate a hash code for a namespace node.
 502  
      *
 503  
      * @return a hash code for this node
 504  
      */
 505  
     public int hashCode ()
 506  
     {
 507  16
         return hashCode(parent) + hashCode(name) + hashCode(value);
 508  
     }
 509  
 
 510  
 
 511  
     /**
 512  
      * Test for equivalence with another object.
 513  
      *
 514  
      * <p>Two Namespace nodes are considered equivalent if their parents,
 515  
      * names, and values are equal.</p>
 516  
      *
 517  
      * @param o the object to test for equality
 518  
      * @return true if the object is equivalent to this node, false
 519  
      *         otherwise
 520  
      */
 521  
     public boolean equals (Object o)
 522  
     {
 523  0
         if (o == this) return true;
 524  0
         else if (o == null) return false;
 525  0
         else if (o instanceof NamespaceNode) {
 526  0
             NamespaceNode ns = (NamespaceNode)o;
 527  0
             return (equals(parent, ns.getParentNode()) &&
 528  
                 equals(name, ns.getNodeName()) &&
 529  
                 equals(value, ns.getNodeValue()));
 530  
         } else {
 531  0
             return false;
 532  
         }
 533  
     }
 534  
 
 535  
 
 536  
     /**
 537  
      * Helper method for generating a hash code.
 538  
      *
 539  
      * @param o the object for generating a hash code (possibly null)
 540  
      * @return the object's hash code, or 0 if the object is null
 541  
      * @see java.lang.Object#hashCode
 542  
      */
 543  
     private int hashCode (Object o)
 544  
     {
 545  48
         return (o == null ? 0 : o.hashCode());
 546  
     }
 547  
 
 548  
 
 549  
     /**
 550  
      * Helper method for comparing two objects.
 551  
      *
 552  
      * @param a the first object to compare (possibly null)
 553  
      * @param b the second object to compare (possibly null)
 554  
      * @return true if the objects are equivalent or are both null
 555  
      * @see java.lang.Object#equals
 556  
      */
 557  
     private boolean equals (Object a, Object b)
 558  
     {
 559  0
         return ((a == null && b == null) ||
 560  
           (a != null && a.equals(b)));
 561  
     }
 562  
 
 563  
 
 564  
     ////////////////////////////////////////////////////////////////////
 565  
     // Internal state.
 566  
     ////////////////////////////////////////////////////////////////////
 567  
 
 568  
     private Node parent;
 569  
     private String name;
 570  
     private String value;
 571  
 
 572  
 
 573  
 
 574  
     ////////////////////////////////////////////////////////////////////
 575  
     // Inner class: empty node list.
 576  
     ////////////////////////////////////////////////////////////////////
 577  
 
 578  
 
 579  
     /**
 580  
      * A node list with no members.
 581  
      *
 582  
      * <p>This class is necessary for the {@link Node#getChildNodes}
 583  
      * method, which must return an empty node list rather than
 584  
      * null when there are no children.</p>
 585  
      */
 586  0
     private static class EmptyNodeList implements NodeList
 587  
     {
 588  
 
 589  
         /**
 590  
          * @see NodeList#getLength
 591  
          */
 592  
         public int getLength ()
 593  
         {
 594  0
             return 0;
 595  
         }
 596  
     
 597  
     
 598  
         /**
 599  
          * @see NodeList#item
 600  
          */
 601  
         public Node item(int index)
 602  
         {
 603  0
             return null;
 604  
         }
 605  
     
 606  
     }
 607  
 
 608  
     ////////////////////////////////////////////////////////////////////
 609  
     // DOM Level 3 methods
 610  
     ////////////////////////////////////////////////////////////////////
 611  
 
 612  
     /**
 613  
      * Return the base URI of the document containing this node. 
 614  
      * This only works in DOM 3.
 615  
      *
 616  
      * @return null
 617  
      */
 618  
     public String getBaseURI() {
 619  2
         Class clazz = Node.class;
 620  
         try {
 621  0
             Class[] args = new Class[0];
 622  0
             Method getBaseURI = clazz.getMethod("getBaseURI", args);
 623  0
             String base = (String) getBaseURI.invoke(this.getParentNode(), args);
 624  0
             return base;
 625  
         }
 626  0
         catch (Exception ex) {
 627  0
             return null;
 628  
         }
 629  
     }
 630  
 
 631  
 
 632  
     /**
 633  
      * Compare relative position of this node to another nbode. (Always fails).
 634  
      * This method is included solely for compatibility with the superclass.
 635  
      * 
 636  
      * @param other the node to compare to
 637  
      *
 638  
      * @return never
 639  
      * @throws DOMException NOT_SUPPORTED_ERR
 640  
      */
 641  
     public short compareDocumentPosition(Node other) throws DOMException {
 642  0
         DOMException ex = new DOMException(
 643  
           DOMException.NOT_SUPPORTED_ERR,
 644  
           "DOM level 3 interfaces are not fully implemented in Jaxen's NamespaceNode class"
 645  
         );
 646  0
         throw ex;
 647  
     }
 648  
 
 649  
 
 650  
     /**
 651  
      * Return the namespace URI.
 652  
      *
 653  
      * @return the namespace URI
 654  
      * @see #getNodeValue
 655  
      */
 656  
     public String getTextContent() {
 657  2
         return value;
 658  
     }
 659  
 
 660  
 
 661  
     /**
 662  
      * Change the value of this node (always fails).
 663  
      * This method is included solely for compatibility with the superclass.
 664  
      *
 665  
      * @param textContent the new content
 666  
      * @throws DOMException always
 667  
      */
 668  
     public void setTextContent(String textContent) throws DOMException {
 669  2
         disallowModification();
 670  0
     }
 671  
 
 672  
 
 673  
     /**
 674  
      * Returns true if and only if this object represents the same XPath namespace node
 675  
      * as the argument; that is, they have the same parent, the same prefix, and the
 676  
      * same URI.
 677  
      * 
 678  
      * @param other the node to compare to
 679  
      * @return true if this object represents the same XPath namespace node
 680  
      *     as other; false otherwise
 681  
      */
 682  
     public boolean isSameNode(Node other)  {
 683  4
         boolean a = this.isEqualNode(other);
 684  
         // a bit flaky (should really be 
 685  
         // this.getParentNode().isEqual(other.getParentNode())
 686  
         // but we want this to compile in Java 1.4 without problems
 687  
         // Note that this will mess up code coverage since you can't cover both
 688  
         // branches in the same VM
 689  
         boolean b;
 690  4
         Node thisParent = this.getParentNode();
 691  4
         Node thatParent = other.getParentNode();
 692  
         try {
 693  4
             Class clazz = Node.class;
 694  4
             Class[] args = {clazz};
 695  4
             Method isEqual = clazz.getMethod("isEqual", args);
 696  0
             Object[] args2 = new Object[1];
 697  0
             args2[0] = thatParent;
 698  0
             Boolean result = (Boolean) isEqual.invoke(thisParent, args2);
 699  0
             b = result.booleanValue();
 700  
         }
 701  4
         catch (NoSuchMethodException ex) {
 702  4
             b = thisParent.equals(thatParent);
 703  
         }
 704  0
         catch (InvocationTargetException ex) {
 705  0
             b = thisParent.equals(thatParent);
 706  
         }
 707  0
         catch (IllegalAccessException ex) {
 708  0
             b = thisParent.equals(thatParent);
 709  4
         }
 710  
         
 711  4
         return a && b;
 712  
         
 713  
     }
 714  
 
 715  
 
 716  
     /**
 717  
      * Return the prefix bound to this namespace URI within the scope
 718  
      * of this node. 
 719  
      * 
 720  
      * @param namespaceURI the URI to find a prefix binding for
 721  
      *
 722  
      * @return a prefix matching this namespace URI
 723  
      * @throws UnsupportedOperationException in DOM 2
 724  
      */
 725  
     public String lookupPrefix(String namespaceURI) {
 726  
         // This could be fully implemented even in Java 1.4. See
 727  
         // http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/namespaces-algorithms.html#lookupNamespaceURIAlgo
 728  
         // It hardly seems worth the effort though.
 729  
         
 730  
         try {
 731  0
             Class clazz = Node.class;
 732  0
             Class[] argTypes = {String.class};
 733  0
             Method lookupPrefix = clazz.getMethod("lookupPrefix", argTypes);
 734  0
             String[] args = {namespaceURI};
 735  0
             String result = (String) lookupPrefix.invoke(parent, args);
 736  0
             return result;
 737  
         }
 738  0
         catch (NoSuchMethodException ex) {
 739  0
             throw new UnsupportedOperationException("Cannot lookup prefixes in DOM 2");
 740  
         }
 741  0
         catch (InvocationTargetException ex) {
 742  0
             throw new UnsupportedOperationException("Cannot lookup prefixes in DOM 2");
 743  
         }
 744  0
         catch (IllegalAccessException ex) {
 745  0
             throw new UnsupportedOperationException("Cannot lookup prefixes in DOM 2");
 746  
         }
 747  
         
 748  
     }
 749  
 
 750  
 
 751  
     /**
 752  
      * Return true if the specified URI is the default namespace in
 753  
      * scope (always fails). This method is included solely for 
 754  
      * compatibility with the superclass.
 755  
      * 
 756  
      * @param namespaceURI the URI to check
 757  
      *
 758  
      * @return never
 759  
      * @throws UnsupportedOperationException always
 760  
      */
 761  
     public boolean isDefaultNamespace(String namespaceURI) {
 762  0
         return namespaceURI.equals(this.lookupNamespaceURI(null));
 763  
     }
 764  
 
 765  
 
 766  
     /**
 767  
      * Return the namespace URI mapped to the specified
 768  
      * prefix within the scope of this namespace node.
 769  
      * 
 770  
      * @param prefix the prefix to search for
 771  
      *
 772  
      * @return the namespace URI mapped to this prefix
 773  
      * @throws UnsupportedOperationException in DOM 2
 774  
      */
 775  
     public String lookupNamespaceURI(String prefix) {
 776  
         // This could be fully implemented even in Java 1.4. See
 777  
         // http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/namespaces-algorithms.html#lookupNamespaceURIAlgo
 778  
         // It hardly seems worth the effort though.
 779  
         
 780  
         try {
 781  0
             Class clazz = Node.class;
 782  0
             Class[] argTypes = {String.class};
 783  0
             Method lookupNamespaceURI = clazz.getMethod("lookupNamespaceURI", argTypes);
 784  0
             String[] args = {prefix};
 785  0
             String result = (String) lookupNamespaceURI.invoke(parent, args);
 786  0
             return result;
 787  
         }
 788  0
         catch (NoSuchMethodException ex) {
 789  0
             throw new UnsupportedOperationException("Cannot lookup namespace URIs in DOM 2");
 790  
         }
 791  0
         catch (InvocationTargetException ex) {
 792  0
             throw new UnsupportedOperationException("Cannot lookup namespace URIs in DOM 2");
 793  
         }
 794  0
         catch (IllegalAccessException ex) {
 795  0
             throw new UnsupportedOperationException("Cannot lookup namespace URIs in DOM 2");
 796  
         }
 797  
     }
 798  
 
 799  
 
 800  
     /**
 801  
      * Returns true if this object binds the same prefix to the same URI.
 802  
      * That is, this object has the same prefix and URI as the argument.
 803  
      * 
 804  
      * @param arg the node to compare to
 805  
      * @return true if this object has the same prefix and URI as the argument; false otherwise
 806  
      */
 807  
     public boolean isEqualNode(Node arg) {
 808  8
         if (arg.getNodeType() == this.getNodeType()) {
 809  8
             NamespaceNode other = (NamespaceNode) arg;
 810  8
             if (other.name == null && this.name != null) return false;
 811  8
             else if (other.name != null && this.name == null) return false;
 812  4
             else if (other.value == null && this.value != null) return false;
 813  4
             else if (other.value != null && this.value == null) return false;
 814  4
             else if (other.name == null && this.name == null) {
 815  4
                 return other.value.equals(this.value);
 816  
             }
 817  
 
 818  0
             return other.name.equals(this.name) && other.value.equals(this.value);
 819  
         }
 820  0
         return false;
 821  
     }
 822  
 
 823  
 
 824  
     /**
 825  
      * Returns the value of the requested feature. Always returns null.
 826  
      * 
 827  
      * @return null
 828  
      */
 829  
     public Object getFeature(String feature, String version) {
 830  2
         return null;
 831  
     }
 832  
 
 833  
     
 834  
     // XXX userdata needs testing
 835  486
     private HashMap userData = new HashMap();
 836  
 
 837  
     /**
 838  
      * Associates an object with a key. 
 839  
      * 
 840  
      * @param key the key by which the data will be retrieved
 841  
      * @param data the object to store with the key
 842  
      * @param handler ignored since namespace nodes cannot be imported, cloned, or renamed
 843  
      * 
 844  
      * @return the value previously associated with this key; or null
 845  
      *     if there isn't any such previous value
 846  
      */
 847  
     public Object setUserData(String key, Object data, UserDataHandler handler) {
 848  0
         Object oldValue = getUserData(key);
 849  0
         userData.put(key, data);
 850  0
         return oldValue;
 851  
     }
 852  
 
 853  
 
 854  
     /**
 855  
      * Returns the user data associated with the given key. 
 856  
      * 
 857  
      * @param key the lookup key
 858  
      * 
 859  
      * @return the object associated with the key; or null if no such object is available
 860  
      */
 861  
     public Object getUserData(String key) {
 862  0
         return userData.get(key);
 863  
     }
 864  
     
 865  
 }
 866  
 
 867  
 // end of NamespaceNode.java