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

This page automatically generated by Maven