001: /*
002: Copyright (C) 2003 Together
003:
004: This library is free software; you can redistribute it and/or
005: modify it under the terms of the GNU Lesser General Public
006: License as published by the Free Software Foundation; either
007: version 2.1 of the License, or (at your option) any later version.
008:
009: This library is distributed in the hope that it will be useful,
010: but WITHOUT ANY WARRANTY; without even the implied warranty of
011: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: Lesser General Public License for more details.
013:
014: You should have received a copy of the GNU Lesser General Public
015: License along with this library; if not, write to the Free Software
016: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: */
018:
019: package org.enhydra.xml;
020:
021: import java.io.File;
022: import java.io.FileOutputStream;
023: import java.util.ArrayList;
024: import java.util.Iterator;
025: import java.util.List;
026: import java.util.HashMap;
027: import java.util.HashMap;
028:
029: import org.w3c.dom.Attr;
030: import org.w3c.dom.Document;
031: import org.w3c.dom.Element;
032: import org.w3c.dom.DOMException;
033: import org.w3c.dom.NamedNodeMap;
034: import org.w3c.dom.Node;
035: import org.w3c.dom.NodeList;
036: import org.w3c.dom.TypeInfo;
037: import org.w3c.dom.UserDataHandler;
038:
039: /**
040: * @author Tweety
041: *
042: * A class representing a node in a meta-data tree, which implements
043: * the <a href="../../../../api/org/w3c/dom/Element.html">
044: *
045: * <p> Namespaces are ignored in this implementation. The terms "tag
046: * name" and "node name" are always considered to be synonymous.
047: *
048: * @version 1.0
049: */
050: public class ElementImpl extends NodeImpl implements Element {
051:
052: /**
053: * A <code>HashMap</code> of <code>AttrImpl</code> nodes representing
054: * attributes.
055: */
056: protected HashMap attributes = null;
057:
058: /**
059: * Constructs an empty <code>ElementImpl</code>.
060: */
061: public ElementImpl() {
062: attributes = new HashMap();
063: type = ELEMENT_NODE;
064: }
065:
066: /**
067: * Constructs a <code>ElementImpl</code> from the given node,
068: * without creating entire children subtree.
069: *
070: * @param element , as a <code>ElementImpl</code>.
071: */
072: public ElementImpl(ElementImpl element) {
073: super (element);
074: attributes = element.attributes;
075: type = ELEMENT_NODE;
076: }
077:
078: /**
079: * Constructs an <code>ElementImpl</code> with the given
080: * document owner and node name.
081: *
082: * @param ownerDoc the document owner of the node, as a <code>Document</code>.
083: * @param name is the name of the node, as a <code>String</code>.
084: */
085: public ElementImpl(Document ownerDoc, String name) {
086: super (ownerDoc, name, ELEMENT_NODE);
087: this .attributes = new HashMap();
088: }
089:
090: /**
091: * Constructs an <code>ElementImpl</code> with the given
092: * document owner, node name, node type and node value.
093: *
094: * @param ownerDoc the document owner of the node, as a <code>Document</code>.
095: * @param nodeName the name of the node, as a <code>String</code>.
096: * @param type the type of the node, as a <code>short</code>.
097: * @param value the value of the node, as a <code>String</code>.
098: */
099: protected ElementImpl(Document ownerDoc, String nodeName,
100: short type, String value) {
101: super (ownerDoc, nodeName, type, value);
102: }
103:
104: /**
105: * Constructs an <code>ElementImpl</code> from a given node (creates the children subtree too),
106: * as a <code>Node</code>
107: *
108: * @param node , as a <code>Node</code>.
109: */
110: public ElementImpl(Node node) {
111: this (node, true);
112: }
113:
114: /**
115: * Constructs an <code>ElementImpl</code> from a given node, as a <code>Node</code>,
116: * and deep as <code>boolean</code>.
117: *
118: * @param node , as a <code>Node</code>.
119: * @param deep if <code>true</code>, recursively clone the subtree
120: * under the specified node; if <code>false</code>, clone only the
121: * node itself.
122: */
123: public ElementImpl(Node node, boolean deep) {
124: super (node, false);
125: attributes = new HashMap();
126: NamedNodeMap attrs = node.getAttributes();
127: if (attrs != null) {
128: for (int i = 0; i < attrs.getLength(); i++) {
129: Attr attr = new AttrImpl((Attr) attrs.item(i));
130: attributes.put(attr.getName(), attr);
131: }
132: }
133: if (deep)
134: initNodeImplChildren(node);
135: }
136:
137: /**
138: * Creates new instance of <code>ElementImpl</code> from a given document
139: * as a <code>Document</code>.
140: *
141: * @param document document.
142: *
143: * @return new <code>Element</code> node as a root of the <code>Document</code>.
144: */
145: public static Element newInstance(Document document) {
146: Node root = document.getDocumentElement();
147: return new ElementImpl(root);
148: }
149:
150: /**
151: * Inserts the node <code>newChild</code> before the existing
152: * child node <code>refChild</code>. If <code>refChild</code> is
153: * <code>null</code>, insert <code>newChild</code> at the end of
154: * the list of children.
155: *
156: * @param newChild the <code>Node</code> to insert.
157: * @param refChild the reference <code>Node</code>.
158: *
159: * @return the node being inserted.
160: *
161: * @exception IllegalArgumentException if <code>newChild</code> is
162: * <code>null</code>.
163: */
164: public Node insertBefore(Node newChild, Node refChild) {
165: super .insertBefore(newChild, refChild);
166: return newChild;
167: }
168:
169: /**
170: * Replaces the child node <code>oldChild</code> with
171: * <code>newChild</code> in the list of children, and returns the
172: * <code>oldChild</code> node.
173: *
174: * @param newChild the <code>Node</code> to insert.
175: * @param oldChild the <code>Node</code> to be replaced.
176: *
177: * @return the node replaced.
178: *
179: * @exception IllegalArgumentException if <code>newChild</code> is
180: * <code>null</code>.
181: */
182: public Node replaceChild(Node newChild, Node oldChild) {
183: super .replaceChild(newChild, oldChild);
184: return oldChild;
185: }
186:
187: /**
188: * Removes the child node indicated by <code>oldChild</code> from
189: * the list of children, and returns it.
190: *
191: * @param oldChild the <code>Node</code> to be removed.
192: *
193: * @return the node removed.
194: *
195: * @exception IllegalArgumentException if <code>oldChild</code> is
196: * <code>null</code>.
197: */
198: public Node removeChild(Node oldChild) {
199: super .removeChild(oldChild);
200: return oldChild;
201: }
202:
203: /**
204: * Returns a duplicate of this node. The duplicate node has no
205: * parent (<code>getParentNode</code> returns <code>null</code>).
206: * If a shallow clone is being performed (<code>deep</code> is
207: * <code>false</code>), the new node will not have any children or
208: * siblings. If a deep clone is being performed, the new node
209: * will form the root of a complete cloned subtree.
210: *
211: * @param deep if <code>true</code>, recursively clone the subtree
212: * under the specified node; if <code>false</code>, clone only the
213: * node itself.
214: *
215: * @return the duplicate node.
216: */
217: public Node cloneNode(boolean deep) {
218: return new ElementImpl(this , deep);
219: }
220:
221: // Methods from Element
222:
223: /**
224: * Returns tag name of this node.
225: *
226: * @return tag name of this node as a <code>String</code>.
227: */
228: public String getTagName() {
229: return nodeName;
230: }
231:
232: /**
233: * Returns all attribute nodes of this node.
234: *
235: * @return all attribute nodes of this node as a <code>NamedNodeMap</code>.
236: */
237: public NamedNodeMap getAttributes() {
238: return new HashMapNamedNodeMap(attributes);
239: }
240:
241: /**
242: * Returns the value of the attribute with given name.
243: *
244: * @param name name of attribute.
245: *
246: * @return value of attribute.
247: */
248: public String getAttribute(String name) {
249: Attr attr = getAttributeNode(name);
250: if (attr == null) {
251: return "";
252: }
253: return attr.getValue();
254: }
255:
256: /**
257: * Equivalent to <code>getAttribute(localName)</code>.
258: *
259: * @see #setAttributeNS
260: * @param namespaceURI is name space
261: * @param localName is string
262: * @return node
263: */
264: public String getAttributeNS(String namespaceURI, String localName) {
265: return getAttribute(localName);
266: }
267:
268: /**
269: * To the <code>name</code> attribute set value to <code>value</code>.
270: *
271: * @param name attribute value.
272: * @param value new attribute value.
273: */
274: public void setAttribute(String name, String value) {
275: // Note minor dependency on Crimson package
276: // Steal the code if Crimson ever goes away
277:
278: // Code below does not work with jdk1.3
279: /*
280: if (!org.apache.crimson.util.XmlNames.isName(name)) {
281: throw new NodeDOMException(
282: DOMException.INVALID_CHARACTER_ERR,
283: "Attribute name is illegal!");
284: }
285: */
286: attributes.put(name, new AttrImpl(this , name, value));
287: }
288:
289: /**
290: * Equivalent to <code>setAttribute(qualifiedName, value)</code>.
291: *
292: * @see #getAttributeNS
293: * @param namespaceURI is name space of the node
294: * @param qualifiedName is string
295: * @param value is value of the node
296: */
297: public void setAttributeNS(String namespaceURI,
298: String qualifiedName, String value) {
299: setAttribute(qualifiedName, value);
300: }
301:
302: /**
303: * Removes attribute with the given name.
304: *
305: * @param name attribute name.
306: */
307: public void removeAttribute(String name) {
308: if (type != ELEMENT_NODE)
309: throw new NodeDOMException(DOMException.NOT_SUPPORTED_ERR,
310: "Node doesn't have attributes");
311: removeAttribute(name, true);
312: }
313:
314: private void removeAttribute(String name, boolean checkPresent) {
315: if (attributes.remove(name) != null)
316: return;
317: // If we get here, the attribute doesn't exist
318: if (checkPresent) {
319: throw new NodeDOMException(DOMException.NOT_FOUND_ERR,
320: "No such attribute!");
321: }
322: }
323:
324: /**
325: * Returns <code>true</code>, if this node has attributes, otherwise
326: * <code>false</code>.
327: *
328: * @return <code>true</code> if node has attributes, otherwise <code>false</code>..
329: */
330: public boolean hasAttributes() {
331: return attributes.size() > 0;
332: }
333:
334: /**
335: * Returns <code>true</code>, if this node has attribute with given name,
336: * otherwise <code>false</code>.
337: *
338: * @return <code>true</code> if node has given attribute, otherwise <code>false</code>..
339: * @param name is name of the node
340: */
341: public boolean hasAttribute(String name) {
342: return getAttributeNode(name) != null;
343: }
344:
345: /**
346: * Equivalent to <code>removeAttribute(localName)</code>.
347: * @param namespaceURI is name space of the node
348: * @param localName is name of the node
349: */
350: public void removeAttributeNS(String namespaceURI, String localName) {
351: removeAttribute(localName);
352: }
353:
354: /**
355: * Returns attribute value with given name of this node.
356: *
357: * @param name name of attribute.
358: *
359: * @return value of attribute.
360: */
361: public Attr getAttributeNode(String name) {
362: return (Attr) attributes.get(name);
363: }
364:
365: /**
366: * Equivalent to <code>getAttributeNode(localName)</code>.
367: *
368: * @see #setAttributeNodeNS
369: * @param namespaceURI is name space of the node
370: * @param localName is name of the node
371: * @return node
372: */
373: public Attr getAttributeNodeNS(String namespaceURI, String localName) {
374: return getAttributeNode(localName);
375: }
376:
377: /**
378: * Add new attribute to this node.
379: *
380: * @param newAttr new attribute.
381: *
382: * @return new attribute as <code>AttrImpl</code>
383: * @throws DOMException
384: */
385: public Attr setAttributeNode(Attr newAttr) throws DOMException {
386: AttrImpl attr;
387: if (newAttr instanceof AttrImpl) {
388: attr = (AttrImpl) newAttr;
389: } else {
390: attr = new AttrImpl(newAttr);
391: }
392: attributes.put(attr.getName(), attr);
393: return attr;
394: }
395:
396: /**
397: * Equivalent to <code>setAttributeNode(newAttr)</code>.
398: *
399: * @see #getAttributeNodeNS
400: * @param newAttr is attribute of the node
401: * @return node
402: */
403: public Attr setAttributeNodeNS(Attr newAttr) {
404: return setAttributeNode(newAttr);
405: }
406:
407: /**
408: * Remove attribute from this node.
409: *
410: * @param oldAttr attribute that will be removed.
411: *
412: * @return old attribute as <code>AttrImpl</code>.
413: */
414: public Attr removeAttributeNode(Attr oldAttr) {
415: removeAttribute(oldAttr.getName());
416: return oldAttr;
417: }
418:
419: /**
420: * Equivalent to <code>hasAttribute(localName)</code>.
421: * @param namespaceURI is name space of the node
422: * @param localName is name of the node
423: * @return node
424: */
425: public boolean hasAttributeNS(String namespaceURI, String localName) {
426: return hasAttribute(localName);
427: }
428:
429: /**
430: * Returns all <code>Element</code> nodes with given name,
431: * searching by all sub nodes from this node.
432: *
433: * @param name tag name.
434: *
435: * @return all <code>Element</code> vith given name as <code>NodeList</code>.
436: */
437: public NodeList getElementsByTagName(String name) {
438: List list = new ArrayList();
439: getElementsByTagName(name, list);
440: return new NodeListImpl(list);
441: }
442:
443: private void getElementsByTagName(String name, List list) {
444: if (nodeName.equals(name)) {
445: list.add(this );
446: }
447:
448: Node child = getFirstChild();
449: while (child != null) {
450: if (child.getNodeType() == Node.ELEMENT_NODE)
451: ((ElementImpl) child).getElementsByTagName(name, list);
452: child = child.getNextSibling();
453: }
454: }
455:
456: /**
457: * Equivalent to <code>getElementsByTagName(localName)</code>.
458: * @param namespaceURI is name space of the node
459: * @param localName is name of the node
460: * @return node
461: */
462: public NodeList getElementsByTagNameNS(String namespaceURI,
463: String localName) {
464: return getElementsByTagName(localName);
465: }
466:
467: /**
468: * Returns <code>true</code> if this node has children nodes.
469: *
470: * @return <code>true</code> if this node has children.
471: */
472: public boolean hasElementChildNodes() {
473: Node child = getFirstChild();
474: while (child != null) {
475: if (child.getNodeType() == Node.ELEMENT_NODE)
476: return true;
477: child = child.getNextSibling();
478: }
479: return false;
480: }
481:
482: /**
483: * Method beginToString for this class writes the xml
484: * begining tag string and all attributes.
485: *
486: * @param sb string buffer to add resulting string.
487: * @param indent used in formating the output.
488: */
489: protected void beginToString(StringBuffer sb, Indent indent) {
490: sb.append("\n" + indent + "<" + this .nodeName);
491:
492: for (Iterator iter = attributes.values().iterator(); iter
493: .hasNext();) {
494: Attr attr = (Attr) iter.next();
495: sb.append(" " + attr.getNodeName() + "=\""
496: + attr.getNodeValue() + "\"");
497: }
498: // if (hasChildNodes()) {
499: sb.append(">");
500: indent.increment();
501: // } else
502: // sb.append("/>");
503: }
504:
505: /**
506: * Check that the node is either <code>null</code> or an
507: * <code>NodeImpl</code>.
508: *
509: * @exception DOMException if node is not an instance of <code>NodeImpl</code>.
510: */
511: // protected void checkNode(Node node) throws DOMException {
512: // if (node == null) {
513: // return;
514: // }
515: // if (!(node instanceof ElementImpl))
516: // throw new NodeDOMException(DOMException.WRONG_DOCUMENT_ERR, "Node is not an instance of ElementImpl!");
517: // }
518: /**
519: * Method endToString for this class writes the xml
520: * ending tag string.
521: *
522: * @param sb string buffer to add resulting string.
523: * @param indent used in formating the output.
524: */
525: protected void endToString(StringBuffer sb, Indent indent) {
526: // if (hasChildNodes()) {
527: indent.decrement();
528: if (hasElementChildNodes())
529: sb.append("\n" + indent + "</" + this .nodeName + ">");
530: else
531: sb.append("</" + this .nodeName + ">");
532: // }
533: }
534:
535: /* METHODS FROM INTERFACE IN JDK1.5 */
536:
537: public TypeInfo getSchemaTypeInfo() {
538: // TODO Auto-generated method stub
539: return null;
540: }
541:
542: public void setIdAttribute(String name, boolean isId)
543: throws DOMException {
544: // TODO Auto-generated method stub
545:
546: }
547:
548: public void setIdAttributeNode(Attr idAttr, boolean isId)
549: throws DOMException {
550: // TODO Auto-generated method stub
551:
552: }
553:
554: public void setIdAttributeNS(String namespaceURI, String localName,
555: boolean isId) throws DOMException {
556: // TODO Auto-generated method stub
557:
558: }
559:
560: public Node appendChild(Node newChild) {
561: // TODO Auto-generated method stub
562: return super .appendChild(newChild);
563: }
564:
565: protected void checkNode(Node node) throws DOMException {
566: // TODO Auto-generated method stub
567: super .checkNode(node);
568: }
569:
570: public short compareDocumentPosition(Node other)
571: throws DOMException {
572: // TODO Auto-generated method stub
573: return super .compareDocumentPosition(other);
574: }
575:
576: public String getBaseURI() {
577: // TODO Auto-generated method stub
578: return super .getBaseURI();
579: }
580:
581: public NodeList getChildNodes() {
582: // TODO Auto-generated method stub
583: return super .getChildNodes();
584: }
585:
586: public Object getFeature(String feature, String version) {
587: // TODO Auto-generated method stub
588: return super .getFeature(feature, version);
589: }
590:
591: public Node getFirstChild() {
592: // TODO Auto-generated method stub
593: return super .getFirstChild();
594: }
595:
596: public Node getLastChild() {
597: // TODO Auto-generated method stub
598: return super .getLastChild();
599: }
600:
601: public int getLength() {
602: // TODO Auto-generated method stub
603: return super .getLength();
604: }
605:
606: public String getLocalName() {
607: // TODO Auto-generated method stub
608: return super .getLocalName();
609: }
610:
611: public String getNamespaceURI() throws DOMException {
612: // TODO Auto-generated method stub
613: return super .getNamespaceURI();
614: }
615:
616: public Node getNextSibling() {
617: // TODO Auto-generated method stub
618: return super .getNextSibling();
619: }
620:
621: public String getNodeName() {
622: // TODO Auto-generated method stub
623: return super .getNodeName();
624: }
625:
626: public short getNodeType() {
627: // TODO Auto-generated method stub
628: return super .getNodeType();
629: }
630:
631: public String getNodeValue() {
632: // TODO Auto-generated method stub
633: return super .getNodeValue();
634: }
635:
636: public Document getOwnerDocument() {
637: // TODO Auto-generated method stub
638: return super .getOwnerDocument();
639: }
640:
641: public Node getParentNode() {
642: // TODO Auto-generated method stub
643: return super .getParentNode();
644: }
645:
646: public String getPrefix() {
647: // TODO Auto-generated method stub
648: return super .getPrefix();
649: }
650:
651: public Node getPreviousSibling() {
652: // TODO Auto-generated method stub
653: return super .getPreviousSibling();
654: }
655:
656: public String getTextContent() throws DOMException {
657: // TODO Auto-generated method stub
658: return super .getTextContent();
659: }
660:
661: public Object getUserData(String key) {
662: // TODO Auto-generated method stub
663: return super .getUserData(key);
664: }
665:
666: public boolean hasChildNodes() {
667: // TODO Auto-generated method stub
668: return super .hasChildNodes();
669: }
670:
671: protected void initNodeImplChildren(Node node) {
672: // TODO Auto-generated method stub
673: super .initNodeImplChildren(node);
674: }
675:
676: public boolean isDefaultNamespace(String namespaceURI) {
677: // TODO Auto-generated method stub
678: return super .isDefaultNamespace(namespaceURI);
679: }
680:
681: public boolean isEqualNode(Node arg) {
682: // TODO Auto-generated method stub
683: return super .isEqualNode(arg);
684: }
685:
686: public boolean isSameNode(Node other) {
687: // TODO Auto-generated method stub
688: return super .isSameNode(other);
689: }
690:
691: public boolean isSupported(String feature, String version) {
692: // TODO Auto-generated method stub
693: return super .isSupported(feature, version);
694: }
695:
696: public Node item(int index) {
697: // TODO Auto-generated method stub
698: return super .item(index);
699: }
700:
701: public String lookupNamespaceURI(String prefix) {
702: // TODO Auto-generated method stub
703: return super .lookupNamespaceURI(prefix);
704: }
705:
706: public String lookupPrefix(String namespaceURI) {
707: // TODO Auto-generated method stub
708: return super .lookupPrefix(namespaceURI);
709: }
710:
711: protected Node newCommentInstance(Node node) {
712: // TODO Auto-generated method stub
713: return super .newCommentInstance(node);
714: }
715:
716: protected Node newDefaultInstance(Node node) {
717: // TODO Auto-generated method stub
718: return super .newDefaultInstance(node);
719: }
720:
721: protected Node newElementInstance(Node node) {
722: // TODO Auto-generated method stub
723: return super .newElementInstance(node);
724: }
725:
726: protected Node newTextInstance(Node node) {
727: // TODO Auto-generated method stub
728: return super .newTextInstance(node);
729: }
730:
731: public void normalize() {
732: // TODO Auto-generated method stub
733: super .normalize();
734: }
735:
736: public void setNodeValue(String nodeValue) {
737: // TODO Auto-generated method stub
738: super .setNodeValue(nodeValue);
739: }
740:
741: public void setPrefix(String prefix) {
742: // TODO Auto-generated method stub
743: super .setPrefix(prefix);
744: }
745:
746: public void setTextContent(String textContent) throws DOMException {
747: // TODO Auto-generated method stub
748: super .setTextContent(textContent);
749: }
750:
751: public Object setUserData(String key, Object data,
752: UserDataHandler handler) {
753: // TODO Auto-generated method stub
754: return super .setUserData(key, data, handler);
755: }
756:
757: public String toString() {
758: // TODO Auto-generated method stub
759: return super .toString();
760: }
761:
762: public String toString(String tab) {
763: // TODO Auto-generated method stub
764: return super.toString(tab);
765: }
766: }
|