View Javadoc
1 /* 2 Copyright (C) 2003 Together 3 4 This library is free software; you can redistribute it and/or 5 modify it under the terms of the GNU Lesser General Public 6 License as published by the Free Software Foundation; either 7 version 2.1 of the License, or (at your option) any later version. 8 9 This library is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 Lesser General Public License for more details. 13 14 You should have received a copy of the GNU Lesser General Public 15 License along with this library; if not, write to the Free Software 16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 */ 18 19 package org.enhydra.xml; 20 21 import java.io.File; 22 import java.io.FileOutputStream; 23 import java.util.ArrayList; 24 import java.util.Iterator; 25 import java.util.List; 26 import java.util.HashMap; 27 import java.util.HashMap; 28 29 import org.w3c.dom.Attr; 30 import org.w3c.dom.Document; 31 import org.w3c.dom.Element; 32 import org.w3c.dom.DOMException; 33 import org.w3c.dom.NamedNodeMap; 34 import org.w3c.dom.Node; 35 import org.w3c.dom.NodeList; 36 import org.w3c.dom.UserDataHandler; 37 38 /*** 39 * @author Tweety 40 * 41 * A class representing a node in a meta-data tree, which implements 42 * the <a href="../../../../api/org/w3c/dom/Node.html"> 43 * 44 * <p> Namespaces are ignored in this implementation. The terms "tag 45 * name" and "node name" are always considered to be synonymous. 46 * 47 * @version 1.0 48 */ 49 public class NodeImpl implements Node, NodeList { 50 51 /*** 52 * Owner document. 53 */ 54 protected Document ownerDocument; 55 56 57 /*** 58 * The name (tag) of the node as a <code>String</code>. 59 */ 60 protected String nodeName = null; 61 62 63 /*** 64 * The value of the node as a <code>String</code>. 65 */ 66 protected String nodeValue = null; 67 68 69 /*** 70 * The type of the node as a <code>short</code>. 71 */ 72 protected short type = ELEMENT_NODE; 73 74 75 /*** 76 * The parent node of this node, or <code>null</code> if this node 77 * forms the root of its own tree. 78 */ 79 protected NodeImpl parent = null; 80 81 82 /*** 83 * The number of child nodes. 84 */ 85 protected int numChildren = 0; 86 87 88 /*** 89 * The first (leftmost) child node of this node, or 90 * <code>null</code> if this node is a leaf node. 91 */ 92 protected NodeImpl firstChild = null; 93 94 95 /*** 96 * The last (rightmost) child node of this node, or 97 * <code>null</code> if this node is a leaf node. 98 */ 99 protected NodeImpl lastChild = null; 100 101 102 /*** 103 * The next (right) sibling node of this node, or 104 * <code>null</code> if this node is its parent's last child node. 105 */ 106 protected NodeImpl nextSibling = null; 107 108 109 /*** 110 * The previous (left) sibling node of this node, or 111 * <code>null</code> if this node is its parent's first child node. 112 */ 113 protected NodeImpl previousSibling = null; 114 115 116 /*** 117 * Constructs an empty <code>NodeImpl</code>. 118 */ 119 public NodeImpl() { 120 } 121 122 123 /*** 124 * Constructs a <code>NodeImpl</code> from the given node, 125 * without creating entire children subtree. 126 * 127 * @param node , as a <code>NodeImpl</code>. 128 */ 129 public NodeImpl(NodeImpl node) { 130 ownerDocument = node.ownerDocument; 131 nodeName = node.nodeName; 132 nodeValue = node.nodeValue; 133 type = node.type; 134 parent = node.parent; 135 numChildren = node.numChildren; 136 firstChild = node.firstChild; 137 lastChild = node.lastChild; 138 nextSibling = node.nextSibling; 139 previousSibling = node.previousSibling; 140 } 141 142 143 /*** 144 * Constructs an <code>NodeImpl</code> from a given node (creates the children subtree too), 145 * as a <code>Node</code> 146 * 147 * @param node , as a <code>Node</code>. 148 */ 149 public NodeImpl(Node node) { 150 this(node, true); 151 } 152 153 154 /*** 155 * Constructs an <code>NodeImpl</code> from a given node, as a <code>Node</code>, 156 * and deep as <code>boolean</code>. 157 * 158 * @param node , as a <code>Node</code>. 159 * @param deep if <code>true</code>, recursively clone the subtree 160 * under the specified node; if <code>false</code>, clone only the 161 * node itself. 162 */ 163 public NodeImpl(Node node, boolean deep) { 164 this.ownerDocument = node.getOwnerDocument(); 165 this.nodeName = node.getNodeName(); 166 this.type = node.getNodeType(); 167 this.nodeValue = node.getNodeValue(); 168 if (deep) 169 this.initNodeImplChildren(node); 170 } 171 172 173 /*** 174 * Constructs a <code>NodeImpl</code> from the given document owner and node name. 175 * 176 * @param ownerDoc the document owner of the node, as a <code>Document</code>. 177 * @param name the name of the node, as a <code>String</code>. 178 */ 179 public NodeImpl(Document ownerDoc, String name) { 180 this.ownerDocument = ownerDoc; 181 this.nodeName = nodeName; 182 } 183 184 185 /*** 186 * Constructs an <code>NodeImpl</code> from a given document owner, 187 * node name and node type. 188 * 189 * @param ownerDoc the document owner of the node, as a <code>Document</code>. 190 * @param nodeName the name of the node, as a <code>String</code>. 191 * @param type the type of the node, as a <code>short</code>. 192 */ 193 public NodeImpl(Document ownerDoc, String nodeName, short type) { 194 this.ownerDocument = ownerDoc; 195 this.nodeName = nodeName; 196 this.type = type; 197 } 198 199 200 /*** 201 * Constructs an <code>NodeImpl</code> from a given document owner, 202 * node name, node type and node value. 203 * 204 * @param ownerDoc the document owner of the node, as a <code>Document</code>. 205 * @param nodeName the name of the node, as a <code>String</code>. 206 * @param type the type of the node, as a <code>short</code>. 207 * @param value the value of the node, as a <code>String</code>. 208 */ 209 public NodeImpl(Document ownerDoc, String nodeName, short type, String value) { 210 this.ownerDocument = ownerDoc; 211 this.nodeName = nodeName; 212 this.type = type; 213 this.nodeValue = value; 214 } 215 216 217 218 /*** 219 * Creates the children subtree and adds to this node. 220 * (this part had to be splited from the constructor) 221 * 222 * @param node a <code>Node</code>. 223 */ 224 protected void initNodeImplChildren(Node node) { 225 // add children 226 Node child = node.getFirstChild(); 227 while (child != null) { 228 switch (child.getNodeType()) { 229 case Node.ELEMENT_NODE : { 230 this.appendChild(newElementInstance(child)); 231 }; break; 232 case Node.TEXT_NODE : { 233 this.appendChild(newTextInstance(child)); 234 }; break; 235 case Node.COMMENT_NODE : { 236 this.appendChild(newCommentInstance(child)); 237 }; break; 238 default : { 239 this.appendChild(newDefaultInstance(child)); 240 }; 241 } 242 child = child.getNextSibling(); 243 } 244 } 245 246 247 /*** 248 * Creates new instance of the ElementImpl class. 249 * 250 * @param node , as a <code>Node</code>. 251 * @return Node new instance of the ElementImpl class. 252 */ 253 protected Node newElementInstance(Node node) { 254 return new ElementImpl(node); 255 } 256 257 /*** 258 * Creates new instance of the TextImpl class. 259 * 260 * @param node , as a <code>Node</code>. 261 * @return Node new instance of the TextImpl class. 262 */ 263 protected Node newTextInstance(Node node) { 264 return new TextImpl(node); 265 } 266 267 /*** 268 * Creates new instance of the CommentImpl class. 269 * 270 * @param node , as a <code>Node</code>. 271 * @return Node new instance of the CommentImpl class. 272 */ 273 protected Node newCommentInstance(Node node) { 274 return new CommentImpl(node); 275 } 276 277 /*** 278 * Creates new instance of the NodeImpl class. 279 * 280 * @param node , as a <code>Node</code>. 281 * @return Node new instance of the NodeImpl class. 282 */ 283 protected Node newDefaultInstance(Node node) { 284 return new NodeImpl(node); 285 } 286 287 288 /*** 289 * Check that the node is either <code>null</code> or an 290 * <code>NodeImpl</code>. 291 * 292 * @param node , as a <code>Node</code>. 293 * @exception DOMException if node is not an instance of <code>NodeImpl</code>. 294 */ 295 protected void checkNode(Node node) throws DOMException { 296 if (node == null) { 297 return; 298 } 299 if (!(node instanceof NodeImpl)) 300 throw new NodeDOMException(DOMException.WRONG_DOCUMENT_ERR, "Node is not an instance of NodeImpl!"); 301 } 302 303 304 305 // Methods from Node 306 307 /*** 308 * Returns the name associated with this node. 309 * 310 * @return the name, as a <code>String</code>. 311 */ 312 public String getNodeName() { 313 return nodeName; 314 } 315 316 317 /*** 318 * Returns the value associated with this node. 319 * 320 * @return the node value, as a <code>String</code>. 321 */ 322 public String getNodeValue() { 323 return nodeValue; 324 } 325 326 327 /*** 328 * Sets the node value of this node. 329 * 330 * @param nodeValue new node value, as a <code>String</code>. 331 */ 332 public void setNodeValue(String nodeValue) { 333 this.nodeValue = nodeValue; 334 } 335 336 337 /*** 338 * Returns the node type. 339 * 340 * @return the <code>short</code> value node type. 341 */ 342 public short getNodeType() { 343 return type; 344 } 345 346 347 /*** 348 * Returns the parent of this node. A <code>null</code> value 349 * indicates that the node is the root of its own tree. To add a 350 * node to an existing tree, use one of the 351 * <code>insertBefore</code>, <code>replaceChild</code>, or 352 * <code>appendChild</code> methods. 353 * 354 * @return the parent, as a <code>Node</code>. 355 * 356 * @see #insertBefore 357 * @see #replaceChild 358 * @see #appendChild 359 */ 360 public Node getParentNode() { 361 return parent; 362 } 363 364 365 /*** 366 * Returns all child nodes of this node, or <code>null</code> if 367 * the node has no children. 368 * 369 * @return all child nodes of this node, as a <code>Node</code>, or 370 * <code>null</code>. 371 */ 372 public NodeList getChildNodes() { 373 return this; 374 } 375 376 377 /*** 378 * Returns the first child of this node, or <code>null</code> if 379 * the node has no children. 380 * 381 * @return the first child, as a <code>Node</code>, or 382 * <code>null</code> 383 */ 384 public Node getFirstChild() { 385 return firstChild; 386 } 387 388 389 /*** 390 * Returns the last child of this node, or <code>null</code> if 391 * the node has no children. 392 * 393 * @return the last child, as a <code>Node</code>, or 394 * <code>null</code>. 395 */ 396 public Node getLastChild() { 397 return lastChild; 398 } 399 400 401 /*** 402 * Returns the previous sibling of this node, or <code>null</code> 403 * if this node has no previous sibling. 404 * 405 * @return the previous sibling, as a <code>Node</code>, or 406 * <code>null</code>. 407 */ 408 public Node getPreviousSibling() { 409 return previousSibling; 410 } 411 412 413 /*** 414 * Returns the next sibling of this node, or <code>null</code> if 415 * the node has no next sibling. 416 * 417 * @return the next sibling, as a <code>Node</code>, or 418 * <code>null</code>. 419 */ 420 public Node getNextSibling() { 421 return nextSibling; 422 } 423 424 425 /*** 426 * Returns <code>null</code>, since <code>NodeImpl</code>s 427 * do not belong to any <code>Document</code>. 428 * 429 * @return document owner as <code>Document</code>. 430 */ 431 public Document getOwnerDocument() { 432 return ownerDocument; 433 } 434 435 436 /*** 437 * Inserts the node <code>newChild</code> before the existing 438 * child node <code>refChild</code>. If <code>refChild</code> is 439 * <code>null</code>, insert <code>newChild</code> at the end of 440 * the list of children. 441 * 442 * @param newChild the <code>Node</code> to insert. 443 * @param refChild the reference <code>Node</code>. 444 * 445 * @return the node being inserted. 446 * 447 * @exception IllegalArgumentException if <code>newChild</code> is 448 * <code>null</code>. 449 */ 450 public Node insertBefore(Node newChild, Node refChild) { 451 if (newChild == null) { 452 throw new IllegalArgumentException("newChild == null!"); 453 } 454 455 checkNode(newChild); 456 checkNode(refChild); 457 458 NodeImpl newChildNode = (NodeImpl) newChild; 459 NodeImpl refChildNode = (NodeImpl) refChild; 460 461 // Siblings, can be null. 462 NodeImpl previous = null; 463 NodeImpl next = null; 464 465 if (refChild == null) { 466 previous = this.lastChild; 467 next = null; 468 this.lastChild = newChildNode; 469 } else { 470 previous = refChildNode.previousSibling; 471 next = refChildNode; 472 } 473 474 if (previous != null) { 475 previous.nextSibling = newChildNode; 476 } 477 if (next != null) { 478 next.previousSibling = newChildNode; 479 } 480 481 newChildNode.parent = this; 482 newChildNode.previousSibling = previous; 483 newChildNode.nextSibling = next; 484 485 // N.B.: O.K. if refChild == null 486 if (this.firstChild == refChildNode) { 487 this.firstChild = newChildNode; 488 } 489 ++numChildren; 490 return newChildNode; 491 } 492 493 494 /*** 495 * Replaces the child node <code>oldChild</code> with 496 * <code>newChild</code> in the list of children, and returns the 497 * <code>oldChild</code> node. 498 * 499 * @param newChild the <code>Node</code> to insert. 500 * @param oldChild the <code>Node</code> to be replaced. 501 * 502 * @return the node replaced. 503 * 504 * @exception IllegalArgumentException if <code>newChild</code> is 505 * <code>null</code>. 506 */ 507 public Node replaceChild(Node newChild, Node oldChild) { 508 if (newChild == null) { 509 throw new IllegalArgumentException("newChild == null!"); 510 } 511 512 checkNode(newChild); 513 checkNode(oldChild); 514 515 NodeImpl newChildNode = (NodeImpl) newChild; 516 NodeImpl oldChildNode = (NodeImpl) oldChild; 517 518 NodeImpl previous = oldChildNode.previousSibling; 519 NodeImpl next = oldChildNode.nextSibling; 520 521 if (previous != null) { 522 previous.nextSibling = newChildNode; 523 } 524 if (next != null) { 525 next.previousSibling = newChildNode; 526 } 527 528 newChildNode.parent = this; 529 newChildNode.previousSibling = previous; 530 newChildNode.nextSibling = next; 531 532 if (firstChild == oldChildNode) { 533 firstChild = newChildNode; 534 } 535 if (lastChild == oldChildNode) { 536 lastChild = newChildNode; 537 } 538 539 oldChildNode.parent = null; 540 oldChildNode.previousSibling = null; 541 oldChildNode.nextSibling = null; 542 543 return oldChildNode; 544 } 545 546 547 /*** 548 * Removes the child node indicated by <code>oldChild</code> from 549 * the list of children, and returns it. 550 * 551 * @param oldChild the <code>Node</code> to be removed. 552 * 553 * @return the node removed. 554 * 555 * @exception IllegalArgumentException if <code>oldChild</code> is 556 * <code>null</code>. 557 */ 558 public Node removeChild(Node oldChild) { 559 if (oldChild == null) { 560 throw new IllegalArgumentException("oldChild == null!"); 561 } 562 checkNode(oldChild); 563 564 NodeImpl oldChildNode = (NodeImpl) oldChild; 565 566 NodeImpl previous = oldChildNode.previousSibling; 567 NodeImpl next = oldChildNode.nextSibling; 568 569 if (previous != null) { 570 previous.nextSibling = next; 571 } 572 if (next != null) { 573 next.previousSibling = previous; 574 } 575 576 if (this.firstChild == oldChildNode) { 577 this.firstChild = next; 578 } 579 if (this.lastChild == oldChildNode) { 580 this.lastChild = previous; 581 } 582 583 oldChildNode.parent = null; 584 oldChildNode.previousSibling = null; 585 oldChildNode.nextSibling = null; 586 587 --numChildren; 588 return oldChildNode; 589 } 590 591 592 /*** 593 * Adds the node <code>newChild</code> to the end of the list of 594 * children of this node. 595 * 596 * @param newChild the <code>Node</code> to insert. 597 * 598 * @return the node added. 599 * 600 * @exception IllegalArgumentException if <code>newChild</code> is 601 * <code>null</code>. 602 */ 603 public Node appendChild(Node newChild) { 604 if (newChild == null) { 605 throw new IllegalArgumentException("newChild == null!"); 606 } 607 checkNode(newChild); 608 609 // insertBefore will increment numChildren 610 return insertBefore(newChild, null); 611 } 612 613 614 /*** 615 * Returns <code>true</code> if this node has child nodes. 616 * 617 * @return <code>true</code> if this node has children. 618 */ 619 public boolean hasChildNodes() { 620 return numChildren > 0; 621 } 622 623 624 /*** 625 * Returns a duplicate of this node. The duplicate node has no 626 * parent (<code>getParentNode</code> returns <code>null</code>). 627 * If a shallow clone is being performed (<code>deep</code> is 628 * <code>false</code>), the new node will not have any children or 629 * siblings. If a deep clone is being performed, the new node 630 * will form the root of a complete cloned subtree. 631 * 632 * @param deep if <code>true</code>, recursively clone the subtree 633 * under the specified node; if <code>false</code>, clone only the 634 * node itself. 635 * 636 * @return the duplicate node. 637 */ 638 public Node cloneNode(boolean deep) { 639 return new NodeImpl(this, deep); 640 } 641 642 643 /*** 644 * Does nothing, since <code>NodeImpl</code>s do not 645 * contain <code>Text</code> children. 646 */ 647 public void normalize() { 648 } 649 650 651 /*** 652 * Returns <code>false</code> since DOM features are not 653 * supported. 654 * 655 * @return <code>false</code>. 656 * 657 * @param feature a <code>String</code>, which is ignored. 658 * @param version a <code>String</code>, which is ignored. 659 */ 660 public boolean isSupported(String feature, String version) { 661 return false; 662 } 663 664 665 /*** 666 * @return <code>null</code>, since namespaces are not supported. 667 * @throws DOMException 668 */ 669 public String getNamespaceURI() throws DOMException { 670 return null; 671 } 672 673 674 /*** 675 * Returns <code>null</code>, since namespaces are not supported. 676 * 677 * @return <code>null</code>. 678 * 679 * @see #setPrefix 680 */ 681 public String getPrefix() { 682 return null; 683 } 684 685 686 /*** 687 * Does nothing, since namespaces are not supported. 688 * 689 * @param prefix a <code>String</code>, which is ignored. 690 * 691 * @see #getPrefix 692 */ 693 public void setPrefix(String prefix) { 694 } 695 696 697 /*** 698 * Equivalent to <code>getNodeName</code>. 699 * 700 * @return the node name, as a <code>String</code>. 701 */ 702 public String getLocalName() { 703 return nodeName; 704 } 705 706 707 /*** 708 * Returns all attribute nodes of this node. 709 * 710 * @return all attribute nodes of this node. 711 */ 712 public NamedNodeMap getAttributes() { 713 return null; 714 } 715 716 717 /*** 718 * Returns <code>true</code>, if this node has attributes, otherwise 719 * <code>false</code>. 720 * 721 * @return <code>true</code> if node has attributes, otherwise <code>false</code>.. 722 */ 723 public boolean hasAttributes() { 724 return false; 725 } 726 727 728 729 730 // Methods from NodeList 731 732 733 /*** 734 * Returns number of child nodes. 735 * 736 * @return all number of child nodes. 737 */ 738 public int getLength() { 739 return numChildren; 740 } 741 742 743 /*** 744 * Returns child node with the given index. 745 * 746 * @return child node with the given index. 747 * @param index represents index 748 */ 749 public Node item(int index) { 750 if (index < 0) { 751 return null; 752 } 753 754 Node child = getFirstChild(); 755 while (child != null && index-- > 0) { 756 child = child.getNextSibling(); 757 } 758 return child; 759 } 760 761 762 763 // String methodes 764 765 /*** 766 * Returns <code>String</code> representation of this node. 767 * 768 * @return <code>String</code> representation of this node. 769 */ 770 public String toString() { 771 return toString(Indent.DEFAULT_TAB); 772 } 773 774 775 /*** 776 * Returns <code>String</code> representation of this node. 777 * 778 * @param tab tab for node indentation. 779 * 780 * @return <code>String</code> representation of this node. 781 */ 782 public String toString(String tab) { 783 StringBuffer sb = new StringBuffer(); 784 this.allToString(sb, new Indent(0,tab)); 785 return sb.toString(); 786 } 787 788 789 /*** 790 * Method beginToString should be redefined in extended classes. 791 * Each type of node has its own <code>beginToString and 792 * <code>endToString</code>. This was added to support 793 * writing of the xml file. The <code>Element</code> 794 * type of node: it writes the beginning tag, then calls 795 * the child's <code>toString</code>, and then writes the ending tag. 796 * 797 * @param sb string buffer to add resulting string. 798 * @param indent used in formating the output. 799 */ 800 protected void beginToString(StringBuffer sb, Indent indent) { 801 } 802 803 804 /*** 805 * Method endToString should be redefined in extended classes. 806 * Each type of node has its own <code>beginToString and 807 * <code>endToString</code>. This was added to support 808 * writing of the xml file. The <code>Element</code> 809 * type of node: it writes the beginning tag, then calls 810 * the child's <code>toString</code>, and then writes the ending tag. 811 * 812 * @param sb string buffer to add resulting string. 813 * @param indent used in formating the output. 814 */ 815 protected void endToString(StringBuffer sb, Indent indent) { 816 } 817 818 819 private void allToString(StringBuffer sb, Indent indent) { 820 this.beginToString(sb, indent); 821 Node child = getFirstChild(); 822 while (child != null) { 823 ((NodeImpl) child).allToString(sb, indent); 824 child = child.getNextSibling(); 825 } 826 this.endToString(sb, indent); 827 } 828 829 830 /* METHODS FROM INTERFACE IN JDK1.5 */ 831 832 public short compareDocumentPosition(Node other) throws DOMException { 833 // TODO Auto-generated method stub 834 return 0; 835 } 836 public String getBaseURI() { 837 // TODO Auto-generated method stub 838 return null; 839 } 840 public Object getFeature(String feature, String version) { 841 // TODO Auto-generated method stub 842 return null; 843 } 844 public String getTextContent() throws DOMException { 845 // TODO Auto-generated method stub 846 return null; 847 } 848 public Object getUserData(String key) { 849 // TODO Auto-generated method stub 850 return null; 851 } 852 public boolean isDefaultNamespace(String namespaceURI) { 853 // TODO Auto-generated method stub 854 return false; 855 } 856 public boolean isEqualNode(Node arg) { 857 // TODO Auto-generated method stub 858 return false; 859 } 860 public boolean isSameNode(Node other) { 861 // TODO Auto-generated method stub 862 return false; 863 } 864 public String lookupNamespaceURI(String prefix) { 865 // TODO Auto-generated method stub 866 return null; 867 } 868 public String lookupPrefix(String namespaceURI) { 869 // TODO Auto-generated method stub 870 return null; 871 } 872 public void setTextContent(String textContent) throws DOMException { 873 // TODO Auto-generated method stub 874 875 } 876 public Object setUserData(String key, Object data, UserDataHandler handler) { 877 // TODO Auto-generated method stub 878 return null; 879 } 880 } 881 882 883

This page was automatically generated by Maven