1 /* 2 * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.imageio.metadata; 27 28 import java.util.ArrayList; 29 import java.util.Iterator; 30 import java.util.List; 31 32 import org.w3c.dom.Attr; 33 import org.w3c.dom.Document; 34 import org.w3c.dom.Element; 35 import org.w3c.dom.DOMException; 36 import org.w3c.dom.NamedNodeMap; 37 import org.w3c.dom.Node; 38 import org.w3c.dom.NodeList; 39 import org.w3c.dom.TypeInfo; 40 import org.w3c.dom.UserDataHandler; 41 42 43 class IIODOMException extends DOMException { 44 private static final long serialVersionUID = -4369510142067447468L; 45 46 public IIODOMException(short code, String message) { 47 super(code, message); 48 } 49 } 50 51 class IIONamedNodeMap implements NamedNodeMap { 52 53 List<? extends Node> nodes; 54 55 public IIONamedNodeMap(List<? extends Node> nodes) { 56 this.nodes = nodes; 57 } 58 59 public int getLength() { 60 return nodes.size(); 61 } 62 63 public Node getNamedItem(String name) { 64 Iterator<? extends Node> iter = nodes.iterator(); 65 while (iter.hasNext()) { 66 Node node = iter.next(); 67 if (name.equals(node.getNodeName())) { 68 return node; 69 } 70 } 71 72 return null; 73 } 74 75 public Node item(int index) { 76 Node node = nodes.get(index); 77 return node; 78 } 79 80 public Node removeNamedItem(java.lang.String name) { 81 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, 82 "This NamedNodeMap is read-only!"); 83 } 84 85 public Node setNamedItem(Node arg) { 86 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, 87 "This NamedNodeMap is read-only!"); 88 } 89 90 /** 91 * Equivalent to {@code getNamedItem(localName)}. 92 */ 93 public Node getNamedItemNS(String namespaceURI, String localName) { 94 return getNamedItem(localName); 95 } 96 97 /** 98 * Equivalent to {@code setNamedItem(arg)}. 99 */ 100 public Node setNamedItemNS(Node arg) { 101 return setNamedItem(arg); 102 } 103 104 /** 105 * Equivalent to {@code removeNamedItem(localName)}. 106 */ 107 public Node removeNamedItemNS(String namespaceURI, String localName) { 108 return removeNamedItem(localName); 109 } 110 } 111 112 class IIONodeList implements NodeList { 113 114 List<? extends Node> nodes; 115 116 public IIONodeList(List<? extends Node> nodes) { 117 this.nodes = nodes; 118 } 119 120 public int getLength() { 121 return nodes.size(); 122 } 123 124 public Node item(int index) { 125 if (index < 0 || index >= nodes.size()) { 126 return null; 127 } 128 return nodes.get(index); 129 } 130 } 131 132 class IIOAttr extends IIOMetadataNode implements Attr { 133 134 Element owner; 135 String name; 136 String value; 137 138 public IIOAttr(Element owner, String name, String value) { 139 this.owner = owner; 140 this.name = name; 141 this.value = value; 142 } 143 144 public String getName() { 145 return name; 146 } 147 148 public String getNodeName() { 149 return name; 150 } 151 152 public short getNodeType() { 153 return ATTRIBUTE_NODE; 154 } 155 156 public boolean getSpecified() { 157 return true; 158 } 159 160 public String getValue() { 161 return value; 162 } 163 164 public String getNodeValue() { 165 return value; 166 } 167 168 public void setValue(String value) { 169 this.value = value; 170 } 171 172 public void setNodeValue(String value) { 173 this.value = value; 174 } 175 176 public Element getOwnerElement() { 177 return owner; 178 } 179 180 public void setOwnerElement(Element owner) { 181 this.owner = owner; 182 } 183 184 /** This method is new in the DOM L3 for Attr interface. 185 * Could throw DOMException here, but its probably OK 186 * to always return false. One reason for this, is we have no good 187 * way to document this exception, since this class, IIOAttr, 188 * is not a public class. The rest of the methods that throw 189 * DOMException are publically documented as such on IIOMetadataNode. 190 * @return false 191 */ 192 public boolean isId() { 193 return false; 194 } 195 196 197 } 198 199 /** 200 * A class representing a node in a meta-data tree, which implements 201 * the {@link Element org.w3c.dom.Element} interface and additionally allows 202 * for the storage of non-textual objects via the 203 * {@code getUserObject} and {@code setUserObject} methods. 204 * 205 * <p> This class is not intended to be used for general XML 206 * processing. In particular, {@code Element} nodes created 207 * within the Image I/O API are not compatible with those created by 208 * Sun's standard implementation of the {@code org.w3.dom} API. 209 * In particular, the implementation is tuned for simple uses and may 210 * not perform well for intensive processing. 211 * 212 * <p> Namespaces are ignored in this implementation. The terms "tag 213 * name" and "node name" are always considered to be synonymous. 214 * 215 * <em>Note:</em> 216 * The DOM Level 3 specification added a number of new methods to the 217 * {@code Node}, {@code Element} and {@code Attr} interfaces that are not 218 * of value to the {@code IIOMetadataNode} implementation or specification. 219 * 220 * Calling such methods on an {@code IIOMetadataNode}, or an {@code Attr} 221 * instance returned from an {@code IIOMetadataNode} will result in a 222 * {@code DOMException} being thrown. 223 * 224 * @see IIOMetadata#getAsTree 225 * @see IIOMetadata#setFromTree 226 * @see IIOMetadata#mergeTree 227 * 228 */ 229 public class IIOMetadataNode implements Element, NodeList { 230 231 /** 232 * The name of the node as a {@code String}. 233 */ 234 private String nodeName = null; 235 236 /** 237 * The value of the node as a {@code String}. The Image I/O 238 * API typically does not make use of the node value. 239 */ 240 private String nodeValue = null; 241 242 /** 243 * The {@code Object} value associated with this node. 244 */ 245 private Object userObject = null; 246 247 /** 248 * The parent node of this node, or {@code null} if this node 249 * forms the root of its own tree. 250 */ 251 private IIOMetadataNode parent = null; 252 253 /** 254 * The number of child nodes. 255 */ 256 private int numChildren = 0; 257 258 /** 259 * The first (leftmost) child node of this node, or 260 * {@code null} if this node is a leaf node. 261 */ 262 private IIOMetadataNode firstChild = null; 263 264 /** 265 * The last (rightmost) child node of this node, or 266 * {@code null} if this node is a leaf node. 267 */ 268 private IIOMetadataNode lastChild = null; 269 270 /** 271 * The next (right) sibling node of this node, or 272 * {@code null} if this node is its parent's last child node. 273 */ 274 private IIOMetadataNode nextSibling = null; 275 276 /** 277 * The previous (left) sibling node of this node, or 278 * {@code null} if this node is its parent's first child node. 279 */ 280 private IIOMetadataNode previousSibling = null; 281 282 /** 283 * A {@code List} of {@code IIOAttr} nodes representing 284 * attributes. 285 */ 286 private List<IIOAttr> attributes = new ArrayList<>(); 287 288 /** 289 * Constructs an empty {@code IIOMetadataNode}. 290 */ 291 public IIOMetadataNode() {} 292 293 /** 294 * Constructs an {@code IIOMetadataNode} with a given node 295 * name. 296 * 297 * @param nodeName the name of the node, as a {@code String}. 298 */ 299 public IIOMetadataNode(String nodeName) { 300 this.nodeName = nodeName; 301 } 302 303 /** 304 * Check that the node is either {@code null} or an 305 * {@code IIOMetadataNode}. 306 * 307 * @throws DOMException if {@code node} is not {@code null} and not an 308 * instance of {@code IIOMetadataNode} 309 */ 310 private void checkNode(Node node) throws DOMException { 311 if (node == null) { 312 return; 313 } 314 if (!(node instanceof IIOMetadataNode)) { 315 throw new IIODOMException(DOMException.WRONG_DOCUMENT_ERR, 316 "Node not an IIOMetadataNode!"); 317 } 318 } 319 320 // Methods from Node 321 322 /** 323 * Returns the node name associated with this node. 324 * 325 * @return the node name, as a {@code String}. 326 */ 327 public String getNodeName() { 328 return nodeName; 329 } 330 331 /** 332 * Returns the value associated with this node. 333 * 334 * @return the node value, as a {@code String}. 335 */ 336 public String getNodeValue(){ 337 return nodeValue; 338 } 339 340 /** 341 * Sets the {@code String} value associated with this node. 342 */ 343 public void setNodeValue(String nodeValue) { 344 this.nodeValue = nodeValue; 345 } 346 347 /** 348 * Returns the node type, which is always 349 * {@code ELEMENT_NODE}. 350 * 351 * @return the {@code short} value {@code ELEMENT_NODE}. 352 */ 353 public short getNodeType() { 354 return ELEMENT_NODE; 355 } 356 357 /** 358 * Returns the parent of this node. A {@code null} value 359 * indicates that the node is the root of its own tree. To add a 360 * node to an existing tree, use one of the 361 * {@code insertBefore}, {@code replaceChild}, or 362 * {@code appendChild} methods. 363 * 364 * @return the parent, as a {@code Node}. 365 * 366 * @see #insertBefore 367 * @see #replaceChild 368 * @see #appendChild 369 */ 370 public Node getParentNode() { 371 return parent; 372 } 373 374 /** 375 * Returns a {@code NodeList} that contains all children of this node. 376 * If there are no children, this is a {@code NodeList} containing 377 * no nodes. 378 * 379 * @return the children as a {@code NodeList} 380 */ 381 public NodeList getChildNodes() { 382 return this; 383 } 384 385 /** 386 * Returns the first child of this node, or {@code null} if 387 * the node has no children. 388 * 389 * @return the first child, as a {@code Node}, or 390 * {@code null} 391 */ 392 public Node getFirstChild() { 393 return firstChild; 394 } 395 396 /** 397 * Returns the last child of this node, or {@code null} if 398 * the node has no children. 399 * 400 * @return the last child, as a {@code Node}, or 401 * {@code null}. 402 */ 403 public Node getLastChild() { 404 return lastChild; 405 } 406 407 /** 408 * Returns the previous sibling of this node, or {@code null} 409 * if this node has no previous sibling. 410 * 411 * @return the previous sibling, as a {@code Node}, or 412 * {@code null}. 413 */ 414 public Node getPreviousSibling() { 415 return previousSibling; 416 } 417 418 /** 419 * Returns the next sibling of this node, or {@code null} if 420 * the node has no next sibling. 421 * 422 * @return the next sibling, as a {@code Node}, or 423 * {@code null}. 424 */ 425 public Node getNextSibling() { 426 return nextSibling; 427 } 428 429 /** 430 * Returns a {@code NamedNodeMap} containing the attributes of 431 * this node. 432 * 433 * @return a {@code NamedNodeMap} containing the attributes of 434 * this node. 435 */ 436 public NamedNodeMap getAttributes() { 437 return new IIONamedNodeMap(attributes); 438 } 439 440 /** 441 * Returns {@code null}, since {@code IIOMetadataNode}s 442 * do not belong to any {@code Document}. 443 * 444 * @return {@code null}. 445 */ 446 public Document getOwnerDocument() { 447 return null; 448 } 449 450 /** 451 * Inserts the node {@code newChild} before the existing 452 * child node {@code refChild}. If {@code refChild} is 453 * {@code null}, insert {@code newChild} at the end of 454 * the list of children. 455 * 456 * @param newChild the {@code Node} to insert. 457 * @param refChild the reference {@code Node}. 458 * 459 * @return the node being inserted. 460 * 461 * @exception IllegalArgumentException if {@code newChild} is 462 * {@code null}. 463 */ 464 public Node insertBefore(Node newChild, 465 Node refChild) { 466 if (newChild == null) { 467 throw new IllegalArgumentException("newChild == null!"); 468 } 469 470 checkNode(newChild); 471 checkNode(refChild); 472 473 IIOMetadataNode newChildNode = (IIOMetadataNode)newChild; 474 IIOMetadataNode refChildNode = (IIOMetadataNode)refChild; 475 476 // Siblings, can be null. 477 IIOMetadataNode previous = null; 478 IIOMetadataNode next = null; 479 480 if (refChild == null) { 481 previous = this.lastChild; 482 next = null; 483 this.lastChild = newChildNode; 484 } else { 485 previous = refChildNode.previousSibling; 486 next = refChildNode; 487 } 488 489 if (previous != null) { 490 previous.nextSibling = newChildNode; 491 } 492 if (next != null) { 493 next.previousSibling = newChildNode; 494 } 495 496 newChildNode.parent = this; 497 newChildNode.previousSibling = previous; 498 newChildNode.nextSibling = next; 499 500 // N.B.: O.K. if refChild == null 501 if (this.firstChild == refChildNode) { 502 this.firstChild = newChildNode; 503 } 504 505 ++numChildren; 506 return newChildNode; 507 } 508 509 /** 510 * Replaces the child node {@code oldChild} with 511 * {@code newChild} in the list of children, and returns the 512 * {@code oldChild} node. 513 * 514 * @param newChild the {@code Node} to insert. 515 * @param oldChild the {@code Node} to be replaced. 516 * 517 * @return the node replaced. 518 * 519 * @exception IllegalArgumentException if {@code newChild} is 520 * {@code null}. 521 */ 522 public Node replaceChild(Node newChild, 523 Node oldChild) { 524 if (newChild == null) { 525 throw new IllegalArgumentException("newChild == null!"); 526 } 527 528 checkNode(newChild); 529 checkNode(oldChild); 530 531 IIOMetadataNode newChildNode = (IIOMetadataNode)newChild; 532 IIOMetadataNode oldChildNode = (IIOMetadataNode)oldChild; 533 534 IIOMetadataNode previous = oldChildNode.previousSibling; 535 IIOMetadataNode next = oldChildNode.nextSibling; 536 537 if (previous != null) { 538 previous.nextSibling = newChildNode; 539 } 540 if (next != null) { 541 next.previousSibling = newChildNode; 542 } 543 544 newChildNode.parent = this; 545 newChildNode.previousSibling = previous; 546 newChildNode.nextSibling = next; 547 548 if (firstChild == oldChildNode) { 549 firstChild = newChildNode; 550 } 551 if (lastChild == oldChildNode) { 552 lastChild = newChildNode; 553 } 554 555 oldChildNode.parent = null; 556 oldChildNode.previousSibling = null; 557 oldChildNode.nextSibling = null; 558 559 return oldChildNode; 560 } 561 562 /** 563 * Removes the child node indicated by {@code oldChild} from 564 * the list of children, and returns it. 565 * 566 * @param oldChild the {@code Node} to be removed. 567 * 568 * @return the node removed. 569 * 570 * @exception IllegalArgumentException if {@code oldChild} is 571 * {@code null}. 572 */ 573 public Node removeChild(Node oldChild) { 574 if (oldChild == null) { 575 throw new IllegalArgumentException("oldChild == null!"); 576 } 577 checkNode(oldChild); 578 579 IIOMetadataNode oldChildNode = (IIOMetadataNode)oldChild; 580 581 IIOMetadataNode previous = oldChildNode.previousSibling; 582 IIOMetadataNode next = oldChildNode.nextSibling; 583 584 if (previous != null) { 585 previous.nextSibling = next; 586 } 587 if (next != null) { 588 next.previousSibling = previous; 589 } 590 591 if (this.firstChild == oldChildNode) { 592 this.firstChild = next; 593 } 594 if (this.lastChild == oldChildNode) { 595 this.lastChild = previous; 596 } 597 598 oldChildNode.parent = null; 599 oldChildNode.previousSibling = null; 600 oldChildNode.nextSibling = null; 601 602 --numChildren; 603 return oldChildNode; 604 } 605 606 /** 607 * Adds the node {@code newChild} to the end of the list of 608 * children of this node. 609 * 610 * @param newChild the {@code Node} to insert. 611 * 612 * @return the node added. 613 * 614 * @exception IllegalArgumentException if {@code newChild} is 615 * {@code null}. 616 */ 617 public Node appendChild(Node newChild) { 618 if (newChild == null) { 619 throw new IllegalArgumentException("newChild == null!"); 620 } 621 checkNode(newChild); 622 623 // insertBefore will increment numChildren 624 return insertBefore(newChild, null); 625 } 626 627 /** 628 * Returns {@code true} if this node has child nodes. 629 * 630 * @return {@code true} if this node has children. 631 */ 632 public boolean hasChildNodes() { 633 return numChildren > 0; 634 } 635 636 /** 637 * Returns a duplicate of this node. The duplicate node has no 638 * parent ({@code getParentNode} returns {@code null}). 639 * If a shallow clone is being performed ({@code deep} is 640 * {@code false}), the new node will not have any children or 641 * siblings. If a deep clone is being performed, the new node 642 * will form the root of a complete cloned subtree. 643 * 644 * @param deep if {@code true}, recursively clone the subtree 645 * under the specified node; if {@code false}, clone only the 646 * node itself. 647 * 648 * @return the duplicate node. 649 */ 650 public Node cloneNode(boolean deep) { 651 IIOMetadataNode newNode = new IIOMetadataNode(this.nodeName); 652 newNode.setUserObject(getUserObject()); 653 // Attributes 654 655 if (deep) { 656 for (IIOMetadataNode child = firstChild; 657 child != null; 658 child = child.nextSibling) { 659 newNode.appendChild(child.cloneNode(true)); 660 } 661 } 662 663 return newNode; 664 } 665 666 /** 667 * Does nothing, since {@code IIOMetadataNode}s do not 668 * contain {@code Text} children. 669 */ 670 public void normalize() { 671 } 672 673 /** 674 * Returns {@code false} since DOM features are not 675 * supported. 676 * 677 * @return {@code false}. 678 * 679 * @param feature a {@code String}, which is ignored. 680 * @param version a {@code String}, which is ignored. 681 */ 682 public boolean isSupported(String feature, String version) { 683 return false; 684 } 685 686 /** 687 * Returns {@code null}, since namespaces are not supported. 688 */ 689 public String getNamespaceURI() throws DOMException { 690 return null; 691 } 692 693 /** 694 * Returns {@code null}, since namespaces are not supported. 695 * 696 * @return {@code null}. 697 * 698 * @see #setPrefix 699 */ 700 public String getPrefix() { 701 return null; 702 } 703 704 /** 705 * Does nothing, since namespaces are not supported. 706 * 707 * @param prefix a {@code String}, which is ignored. 708 * 709 * @see #getPrefix 710 */ 711 public void setPrefix(String prefix) { 712 } 713 714 /** 715 * Equivalent to {@code getNodeName}. 716 * 717 * @return the node name, as a {@code String}. 718 */ 719 public String getLocalName() { 720 return nodeName; 721 } 722 723 // Methods from Element 724 725 726 /** 727 * Equivalent to {@code getNodeName}. 728 * 729 * @return the node name, as a {@code String} 730 */ 731 public String getTagName() { 732 return nodeName; 733 } 734 735 /** 736 * Retrieves an attribute value by name. 737 * @param name The name of the attribute to retrieve. 738 * @return The {@code Attr} value as a string, or the empty string 739 * if that attribute does not have a specified or default value. 740 */ 741 public String getAttribute(String name) { 742 Attr attr = getAttributeNode(name); 743 if (attr == null) { 744 return ""; 745 } 746 return attr.getValue(); 747 } 748 749 /** 750 * Equivalent to {@code getAttribute(localName)}. 751 * 752 * @see #setAttributeNS 753 */ 754 public String getAttributeNS(String namespaceURI, String localName) { 755 return getAttribute(localName); 756 } 757 758 public void setAttribute(String name, String value) { 759 // Name must be valid unicode chars 760 boolean valid = true; 761 char[] chs = name.toCharArray(); 762 for (int i=0;i<chs.length;i++) { 763 if (chs[i] >= 0xfffe) { 764 valid = false; 765 break; 766 } 767 } 768 if (!valid) { 769 throw new IIODOMException(DOMException.INVALID_CHARACTER_ERR, 770 "Attribute name is illegal!"); 771 } 772 removeAttribute(name, false); 773 attributes.add(new IIOAttr(this, name, value)); 774 } 775 776 /** 777 * Equivalent to {@code setAttribute(qualifiedName, value)}. 778 * 779 * @see #getAttributeNS 780 */ 781 public void setAttributeNS(String namespaceURI, 782 String qualifiedName, String value) { 783 setAttribute(qualifiedName, value); 784 } 785 786 public void removeAttribute(String name) { 787 removeAttribute(name, true); 788 } 789 790 private void removeAttribute(String name, boolean checkPresent) { 791 int numAttributes = attributes.size(); 792 for (int i = 0; i < numAttributes; i++) { 793 IIOAttr attr = attributes.get(i); 794 if (name.equals(attr.getName())) { 795 attr.setOwnerElement(null); 796 attributes.remove(i); 797 return; 798 } 799 } 800 801 // If we get here, the attribute doesn't exist 802 if (checkPresent) { 803 throw new IIODOMException(DOMException.NOT_FOUND_ERR, 804 "No such attribute!"); 805 } 806 } 807 808 /** 809 * Equivalent to {@code removeAttribute(localName)}. 810 */ 811 public void removeAttributeNS(String namespaceURI, 812 String localName) { 813 removeAttribute(localName); 814 } 815 816 public Attr getAttributeNode(String name) { 817 Node node = getAttributes().getNamedItem(name); 818 return (Attr)node; 819 } 820 821 /** 822 * Equivalent to {@code getAttributeNode(localName)}. 823 * 824 * @see #setAttributeNodeNS 825 */ 826 public Attr getAttributeNodeNS(String namespaceURI, 827 String localName) { 828 return getAttributeNode(localName); 829 } 830 831 public Attr setAttributeNode(Attr newAttr) throws DOMException { 832 Element owner = newAttr.getOwnerElement(); 833 if (owner != null) { 834 if (owner == this) { 835 return null; 836 } else { 837 throw new DOMException(DOMException.INUSE_ATTRIBUTE_ERR, 838 "Attribute is already in use"); 839 } 840 } 841 842 IIOAttr attr; 843 if (newAttr instanceof IIOAttr) { 844 attr = (IIOAttr)newAttr; 845 attr.setOwnerElement(this); 846 } else { 847 attr = new IIOAttr(this, 848 newAttr.getName(), 849 newAttr.getValue()); 850 } 851 852 Attr oldAttr = getAttributeNode(attr.getName()); 853 if (oldAttr != null) { 854 removeAttributeNode(oldAttr); 855 } 856 857 attributes.add(attr); 858 859 return oldAttr; 860 } 861 862 /** 863 * Equivalent to {@code setAttributeNode(newAttr)}. 864 * 865 * @see #getAttributeNodeNS 866 */ 867 public Attr setAttributeNodeNS(Attr newAttr) { 868 return setAttributeNode(newAttr); 869 } 870 871 public Attr removeAttributeNode(Attr oldAttr) { 872 removeAttribute(oldAttr.getName()); 873 return oldAttr; 874 } 875 876 public NodeList getElementsByTagName(String name) { 877 List<Node> l = new ArrayList<>(); 878 getElementsByTagName(name, l); 879 return new IIONodeList(l); 880 } 881 882 private void getElementsByTagName(String name, List<Node> l) { 883 if (nodeName.equals(name) || "*".equals(name)) { 884 l.add(this); 885 } 886 887 Node child = getFirstChild(); 888 while (child != null) { 889 ((IIOMetadataNode)child).getElementsByTagName(name, l); 890 child = child.getNextSibling(); 891 } 892 } 893 894 /** 895 * Equivalent to {@code getElementsByTagName(localName)}. 896 */ 897 public NodeList getElementsByTagNameNS(String namespaceURI, 898 String localName) { 899 return getElementsByTagName(localName); 900 } 901 902 public boolean hasAttributes() { 903 return attributes.size() > 0; 904 } 905 906 public boolean hasAttribute(String name) { 907 return getAttributeNode(name) != null; 908 } 909 910 /** 911 * Equivalent to {@code hasAttribute(localName)}. 912 */ 913 public boolean hasAttributeNS(String namespaceURI, 914 String localName) { 915 return hasAttribute(localName); 916 } 917 918 // Methods from NodeList 919 920 public int getLength() { 921 return numChildren; 922 } 923 924 public Node item(int index) { 925 if (index < 0) { 926 return null; 927 } 928 929 Node child = getFirstChild(); 930 while (child != null && index-- > 0) { 931 child = child.getNextSibling(); 932 } 933 return child; 934 } 935 936 /** 937 * Returns the {@code Object} value associated with this node. 938 * 939 * @return the user {@code Object}. 940 * 941 * @see #setUserObject 942 */ 943 public Object getUserObject() { 944 return userObject; 945 } 946 947 /** 948 * Sets the value associated with this node. 949 * 950 * @param userObject the user {@code Object}. 951 * 952 * @see #getUserObject 953 */ 954 public void setUserObject(Object userObject) { 955 this.userObject = userObject; 956 } 957 958 // Start of dummy methods for DOM L3. 959 960 /** 961 * This DOM Level 3 method is not supported for {@code IIOMetadataNode} 962 * and will throw a {@code DOMException}. 963 * @throws DOMException always. 964 */ 965 public void setIdAttribute(String name, 966 boolean isId) 967 throws DOMException { 968 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, 969 "Method not supported"); 970 } 971 972 /** 973 * This DOM Level 3 method is not supported for {@code IIOMetadataNode} 974 * and will throw a {@code DOMException}. 975 * @throws DOMException always. 976 */ 977 public void setIdAttributeNS(String namespaceURI, 978 String localName, 979 boolean isId) 980 throws DOMException { 981 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, 982 "Method not supported"); 983 } 984 985 /** 986 * This DOM Level 3 method is not supported for {@code IIOMetadataNode} 987 * and will throw a {@code DOMException}. 988 * @throws DOMException always. 989 */ 990 public void setIdAttributeNode(Attr idAttr, 991 boolean isId) 992 throws DOMException { 993 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, 994 "Method not supported"); 995 } 996 997 /** 998 * This DOM Level 3 method is not supported for {@code IIOMetadataNode} 999 * and will throw a {@code DOMException}. 1000 * @throws DOMException always. 1001 */ 1002 public TypeInfo getSchemaTypeInfo() throws DOMException { 1003 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, 1004 "Method not supported"); 1005 } 1006 1007 /** 1008 * This DOM Level 3 method is not supported for {@code IIOMetadataNode} 1009 * and will throw a {@code DOMException}. 1010 * @throws DOMException always. 1011 */ 1012 public Object setUserData(String key, 1013 Object data, 1014 UserDataHandler handler) throws DOMException { 1015 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, 1016 "Method not supported"); 1017 } 1018 1019 /** 1020 * This DOM Level 3 method is not supported for {@code IIOMetadataNode} 1021 * and will throw a {@code DOMException}. 1022 * @throws DOMException always. 1023 */ 1024 public Object getUserData(String key) throws DOMException { 1025 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, 1026 "Method not supported"); 1027 } 1028 1029 /** 1030 * This DOM Level 3 method is not supported for {@code IIOMetadataNode} 1031 * and will throw a {@code DOMException}. 1032 * @throws DOMException always. 1033 */ 1034 public Object getFeature(String feature, String version) 1035 throws DOMException { 1036 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, 1037 "Method not supported"); 1038 } 1039 1040 /** 1041 * This DOM Level 3 method is not supported for {@code IIOMetadataNode} 1042 * and will throw a {@code DOMException}. 1043 * @throws DOMException always. 1044 */ 1045 public boolean isSameNode(Node node) throws DOMException { 1046 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, 1047 "Method not supported"); 1048 } 1049 1050 /** 1051 * This DOM Level 3 method is not supported for {@code IIOMetadataNode} 1052 * and will throw a {@code DOMException}. 1053 * @throws DOMException always. 1054 */ 1055 public boolean isEqualNode(Node node) throws DOMException { 1056 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, 1057 "Method not supported"); 1058 } 1059 1060 /** 1061 * This DOM Level 3 method is not supported for {@code IIOMetadataNode} 1062 * and will throw a {@code DOMException}. 1063 * @throws DOMException always. 1064 */ 1065 public String lookupNamespaceURI(String prefix) throws DOMException { 1066 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, 1067 "Method not supported"); 1068 } 1069 1070 /** 1071 * This DOM Level 3 method is not supported for {@code IIOMetadataNode} 1072 * and will throw a {@code DOMException}. 1073 * @throws DOMException always. 1074 */ 1075 public boolean isDefaultNamespace(String namespaceURI) 1076 throws DOMException { 1077 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, 1078 "Method not supported"); 1079 } 1080 1081 /** 1082 * This DOM Level 3 method is not supported for {@code IIOMetadataNode} 1083 * and will throw a {@code DOMException}. 1084 * @throws DOMException always. 1085 */ 1086 public String lookupPrefix(String namespaceURI) throws DOMException { 1087 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, 1088 "Method not supported"); 1089 } 1090 1091 /** 1092 * This DOM Level 3 method is not supported for {@code IIOMetadataNode} 1093 * and will throw a {@code DOMException}. 1094 * @throws DOMException always. 1095 */ 1096 public String getTextContent() throws DOMException { 1097 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, 1098 "Method not supported"); 1099 } 1100 1101 /** 1102 * This DOM Level 3 method is not supported for {@code IIOMetadataNode} 1103 * and will throw a {@code DOMException}. 1104 * @throws DOMException always. 1105 */ 1106 public void setTextContent(String textContent) throws DOMException { 1107 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, 1108 "Method not supported"); 1109 } 1110 1111 /** 1112 * This DOM Level 3 method is not supported for {@code IIOMetadataNode} 1113 * and will throw a {@code DOMException}. 1114 * @throws DOMException always. 1115 */ 1116 public short compareDocumentPosition(Node other) 1117 throws DOMException { 1118 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, 1119 "Method not supported"); 1120 } 1121 1122 /** 1123 * This DOM Level 3 method is not supported for {@code IIOMetadataNode} 1124 * and will throw a {@code DOMException}. 1125 * @throws DOMException always. 1126 */ 1127 public String getBaseURI() throws DOMException { 1128 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, 1129 "Method not supported"); 1130 } 1131 //End of dummy methods for DOM L3. 1132 1133 1134 }