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