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