001: /*
002: * @(#)ElementImpl.java 1.36 02/03/21
003: *
004: * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
005: * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
006: */
007: package org.enhydra.xml;
008:
009: import java.util.ArrayList;
010: import java.util.HashMap;
011: import java.util.Iterator;
012: import java.util.List;
013:
014: import org.w3c.dom.Attr;
015: import org.w3c.dom.DOMException;
016: import org.w3c.dom.Document;
017: import org.w3c.dom.Element;
018: import org.w3c.dom.NamedNodeMap;
019: import org.w3c.dom.Node;
020: import org.w3c.dom.NodeList;
021: import org.w3c.dom.TypeInfo;
022: import org.w3c.dom.UserDataHandler;
023:
024: /**
025: * @author Tweety
026: *
027: * A class representing a node in a meta-data tree, which implements
028: * the <a href="../../../../api/org/w3c/dom/Element.html">
029: *
030: * <p> Namespaces are ignored in this implementation. The terms "tag
031: * name" and "node name" are always considered to be synonymous.
032: *
033: * @version 1.0
034: */
035: public class ElementImpl extends NodeImpl implements Element {
036:
037: /**
038: * A <code>HashMap</code> of <code>AttrImpl</code> nodes representing
039: * attributes.
040: */
041: protected HashMap attributes = null;
042:
043: /** Name start character mask. */
044: public static final int MASK_NAME_START = 0x04;
045:
046: /** Name character mask. */
047: public static final int MASK_NAME = 0x08;
048:
049: /** Character flags. */
050: private static final byte[] CHARS = new byte[1 << 16];
051:
052: /**
053: * Constructs an empty <code>ElementImpl</code>.
054: */
055: public ElementImpl() {
056: attributes = new HashMap();
057: type = ELEMENT_NODE;
058: }
059:
060: /**
061: * Constructs a <code>ElementImpl</code> from the given node,
062: * without creating entire children subtree.
063: *
064: * @param element, as a <code>ElementImpl</code>.
065: */
066: public ElementImpl(ElementImpl element) {
067: super (element);
068: attributes = element.attributes;
069: type = ELEMENT_NODE;
070: }
071:
072: /**
073: * Constructs an <code>ElementImpl</code> with the given
074: * document owner and node name.
075: *
076: * @param ownerDoc the document owner of the node, as a <code>Document</code>.
077: * @param nodeName the name of the node, as a <code>String</code>.
078: */
079: public ElementImpl(Document ownerDoc, String name) {
080: super (ownerDoc, name, ELEMENT_NODE);
081: this .attributes = new HashMap();
082: }
083:
084: /**
085: * Constructs an <code>ElementImpl</code> with the given
086: * document owner, node name, node type and node value.
087: *
088: * @param ownerDoc the document owner of the node, as a <code>Document</code>.
089: * @param nodeName the name of the node, as a <code>String</code>.
090: * @param type the type of the node, as a <code>short</code>.
091: * @param value the value of the node, as a <code>String</code>.
092: */
093: protected ElementImpl(Document ownerDoc, String nodeName,
094: short type, String value) {
095: super (ownerDoc, nodeName, type, value);
096: }
097:
098: /**
099: * Constructs an <code>ElementImpl</code> from a given node (creates the children subtree too),
100: * as a <code>Node</code>
101: *
102: * @param node, as a <code>Node</code>.
103: */
104: public ElementImpl(Node node) {
105: this (node, true);
106: }
107:
108: /**
109: * Constructs an <code>ElementImpl</code> from a given node, as a <code>Node</code>,
110: * and deep as <code>boolean</code>.
111: *
112: * @param node, as a <code>Node</code>.
113: * @param deep if <code>true</code>, recursively clone the subtree
114: * under the specified node; if <code>false</code>, clone only the
115: * node itself.
116: */
117: public ElementImpl(Node node, boolean deep) {
118: super (node, false);
119: attributes = new HashMap();
120: NamedNodeMap attrs = node.getAttributes();
121: if (attrs != null) {
122: for (int i = 0; i < attrs.getLength(); i++) {
123: Attr attr = new AttrImpl((Attr) attrs.item(i));
124: attributes.put(attr.getName(), attr);
125: }
126: }
127: if (deep)
128: initNodeImplChildren(node);
129: }
130:
131: /**
132: * Creates new instance of <code>ElementImpl</code> from a given document
133: * as a <code>Document</code>.
134: *
135: * @param document document.
136: *
137: * @return new <code>Element</code> node as a root of the <code>Document</code>.
138: */
139: public static Element newInstance(Document document) {
140: Node root = document.getDocumentElement();
141: return new ElementImpl(root);
142: }
143:
144: /**
145: * Inserts the node <code>newChild</code> before the existing
146: * child node <code>refChild</code>. If <code>refChild</code> is
147: * <code>null</code>, insert <code>newChild</code> at the end of
148: * the list of children.
149: *
150: * @param newChild the <code>Node</code> to insert.
151: * @param refChild the reference <code>Node</code>.
152: *
153: * @return the node being inserted.
154: *
155: * @exception IllegalArgumentException if <code>newChild</code> is
156: * <code>null</code>.
157: */
158: public Node insertBefore(Node newChild, Node refChild) {
159: super .insertBefore(newChild, refChild);
160: return newChild;
161: }
162:
163: /**
164: * Replaces the child node <code>oldChild</code> with
165: * <code>newChild</code> in the list of children, and returns the
166: * <code>oldChild</code> node.
167: *
168: * @param newChild the <code>Node</code> to insert.
169: * @param oldChild the <code>Node</code> to be replaced.
170: *
171: * @return the node replaced.
172: *
173: * @exception IllegalArgumentException if <code>newChild</code> is
174: * <code>null</code>.
175: */
176: public Node replaceChild(Node newChild, Node oldChild) {
177: super .replaceChild(newChild, oldChild);
178: return oldChild;
179: }
180:
181: /**
182: * Removes the child node indicated by <code>oldChild</code> from
183: * the list of children, and returns it.
184: *
185: * @param oldChild the <code>Node</code> to be removed.
186: *
187: * @return the node removed.
188: *
189: * @exception IllegalArgumentException if <code>oldChild</code> is
190: * <code>null</code>.
191: */
192: public Node removeChild(Node oldChild) {
193: super .removeChild(oldChild);
194: return oldChild;
195: }
196:
197: /**
198: * Returns a duplicate of this node. The duplicate node has no
199: * parent (<code>getParentNode</code> returns <code>null</code>).
200: * If a shallow clone is being performed (<code>deep</code> is
201: * <code>false</code>), the new node will not have any children or
202: * siblings. If a deep clone is being performed, the new node
203: * will form the root of a complete cloned subtree.
204: *
205: * @param deep if <code>true</code>, recursively clone the subtree
206: * under the specified node; if <code>false</code>, clone only the
207: * node itself.
208: *
209: * @return the duplicate node.
210: */
211: public Node cloneNode(boolean deep) {
212: return new ElementImpl(this , deep);
213: }
214:
215: // Methods from Element
216:
217: /**
218: * Returns tag name of this node.
219: *
220: * @return tag name of this node as a <code>String</code>.
221: */
222: public String getTagName() {
223: return nodeName;
224: }
225:
226: /**
227: * Returns all attribute nodes of this node.
228: *
229: * @return all attribute nodes of this node as a <code>NamedNodeMap</code>.
230: */
231: public NamedNodeMap getAttributes() {
232: return new HashMapNamedNodeMap(attributes);
233: }
234:
235: /**
236: * Returns the value of the attribute with given name.
237: *
238: * @param name name of attribute.
239: *
240: * @return value of attribute.
241: */
242: public String getAttribute(String name) {
243: Attr attr = getAttributeNode(name);
244: if (attr == null) {
245: return "";
246: }
247: return attr.getValue();
248: }
249:
250: /**
251: * Equivalent to <code>getAttribute(localName)</code>.
252: *
253: * @see #setAttributeNS
254: */
255: public String getAttributeNS(String namespaceURI, String localName) {
256: return getAttribute(localName);
257: }
258:
259: /**
260: * To the <code>name</code> attribute set value to <code>value</code>.
261: *
262: * @param name attribute value.
263: * @param value new attribute value.
264: */
265: public void setAttribute(String name, String value) {
266: if (!isValidName(name)) {
267: throw new NodeDOMException(
268: DOMException.INVALID_CHARACTER_ERR,
269: "Attribute name is illegal!");
270: }
271: attributes.put(name, new AttrImpl(this , name, value));
272: }
273:
274: /**
275: * Equivalent to <code>setAttribute(qualifiedName, value)</code>.
276: *
277: * @see #getAttributeNS
278: */
279: public void setAttributeNS(String namespaceURI,
280: String qualifiedName, String value) {
281: setAttribute(qualifiedName, value);
282: }
283:
284: /**
285: * Removes attribute with the given name.
286: *
287: * @param name attribute name.
288: */
289: public void removeAttribute(String name) {
290: if (type != ELEMENT_NODE)
291: throw new NodeDOMException(DOMException.NOT_SUPPORTED_ERR,
292: "Node doesn't have attributes");
293: removeAttribute(name, true);
294: }
295:
296: private void removeAttribute(String name, boolean checkPresent) {
297: if (attributes.remove(name) != null)
298: return;
299: // If we get here, the attribute doesn't exist
300: if (checkPresent) {
301: throw new NodeDOMException(DOMException.NOT_FOUND_ERR,
302: "No such attribute!");
303: }
304: }
305:
306: /**
307: * Returns <code>true</code>, if this node has attributes, otherwise
308: * <code>false</code>.
309: *
310: * @return <code>true</code> if node has attributes, otherwise <code>false</code>..
311: */
312: public boolean hasAttributes() {
313: return attributes.size() > 0;
314: }
315:
316: /**
317: * Returns <code>true</code>, if this node has attribute with given name,
318: * otherwise <code>false</code>.
319: *
320: * @return <code>true</code> if node has given attribute, otherwise <code>false</code>..
321: */
322: public boolean hasAttribute(String name) {
323: return getAttributeNode(name) != null;
324: }
325:
326: /**
327: * Equivalent to <code>removeAttribute(localName)</code>.
328: */
329: public void removeAttributeNS(String namespaceURI, String localName) {
330: removeAttribute(localName);
331: }
332:
333: /**
334: * Returns attribute value with given name of this node.
335: *
336: * @param name name of attribute.
337: *
338: * @return value of attribute.
339: */
340: public Attr getAttributeNode(String name) {
341: return (Attr) attributes.get(name);
342: }
343:
344: /**
345: * Equivalent to <code>getAttributeNode(localName)</code>.
346: *
347: * @see #setAttributeNodeNS
348: */
349: public Attr getAttributeNodeNS(String namespaceURI, String localName) {
350: return getAttributeNode(localName);
351: }
352:
353: /**
354: * Add new attribute to this node.
355: *
356: * @param newAttr new attribute.
357: *
358: * @return new attribute as <code>AttrImpl</code>.
359: */
360: public Attr setAttributeNode(Attr newAttr) throws DOMException {
361: AttrImpl attr;
362: if (newAttr instanceof AttrImpl) {
363: attr = (AttrImpl) newAttr;
364: } else {
365: attr = new AttrImpl(newAttr);
366: }
367: attributes.put(attr.getName(), attr);
368: return attr;
369: }
370:
371: /**
372: * Equivalent to <code>setAttributeNode(newAttr)</code>.
373: *
374: * @see #getAttributeNodeNS
375: */
376: public Attr setAttributeNodeNS(Attr newAttr) {
377: return setAttributeNode(newAttr);
378: }
379:
380: /**
381: * Remove attribute from this node.
382: *
383: * @param oldAttr attribute that will be removed.
384: *
385: * @return old attribute as <code>AttrImpl</code>.
386: */
387: public Attr removeAttributeNode(Attr oldAttr) {
388: removeAttribute(oldAttr.getName());
389: return oldAttr;
390: }
391:
392: /**
393: * Equivalent to <code>hasAttribute(localName)</code>.
394: */
395: public boolean hasAttributeNS(String namespaceURI, String localName) {
396: return hasAttribute(localName);
397: }
398:
399: /**
400: * Returns all <code>Element</code> nodes with given name,
401: * searching by all sub nodes from this node.
402: *
403: * @param name tag name.
404: *
405: * @return all <code>Element</code> vith given name as <code>NodeList</code>.
406: */
407: public NodeList getElementsByTagName(String name) {
408: List list = new ArrayList();
409: getElementsByTagName(name, list);
410: return new NodeListImpl(list);
411: }
412:
413: private void getElementsByTagName(String name, List list) {
414: if (nodeName.equals(name)) {
415: list.add(this );
416: }
417:
418: Node child = getFirstChild();
419: while (child != null) {
420: if (child.getNodeType() == Node.ELEMENT_NODE)
421: ((ElementImpl) child).getElementsByTagName(name, list);
422: child = child.getNextSibling();
423: }
424: }
425:
426: /**
427: * Equivalent to <code>getElementsByTagName(localName)</code>.
428: */
429: public NodeList getElementsByTagNameNS(String namespaceURI,
430: String localName) {
431: return getElementsByTagName(localName);
432: }
433:
434: /**
435: * Returns <code>true</code> if this node has children nodes.
436: *
437: * @return <code>true</code> if this node has children.
438: */
439: public boolean hasElementChildNodes() {
440: Node child = getFirstChild();
441: while (child != null) {
442: if (child.getNodeType() == Node.ELEMENT_NODE)
443: return true;
444: child = child.getNextSibling();
445: }
446: return false;
447: }
448:
449: /**
450: * Method beginToString for this class writes the xml
451: * begining tag string and all attributes.
452: *
453: * @param sb string buffer to add resulting string.
454: * @param indent used in formating the output.
455: */
456: protected void beginToString(StringBuffer sb, Indent indent) {
457: sb.append("\n" + indent + "<" + this .nodeName);
458:
459: for (Iterator iter = attributes.values().iterator(); iter
460: .hasNext();) {
461: Attr attr = (Attr) iter.next();
462: sb.append(" " + attr.getNodeName() + "=\""
463: + attr.getNodeValue() + "\"");
464: }
465: if (hasChildNodes()) {
466: sb.append(">");
467: indent.increment();
468: } else
469: sb.append("/>");
470: }
471:
472: /**
473: * Method endToString for this class writes the xml
474: * ending tag string.
475: *
476: * @param sb string buffer to add resulting string.
477: * @param indent used in formating the output.
478: */
479: protected void endToString(StringBuffer sb, Indent indent) {
480: if (hasChildNodes()) {
481: indent.decrement();
482: if (hasElementChildNodes())
483: sb.append("\n" + indent + "</" + this .nodeName + ">");
484: else
485: sb.append("</" + this .nodeName + ">");
486: }
487: }
488:
489: /**
490: * Check to see if a string is a valid Name according to [5]
491: * in the XML 1.0 Recommendation
492: *
493: * @param name string to check
494: * @return true if name is a valid Name
495: */
496: public static boolean isValidName(String name) {
497: if (name.length() == 0)
498: return false;
499: char ch = name.charAt(0);
500: if (!(ch < 0x10000 && (CHARS[ch] & MASK_NAME_START) != 0))
501: return false;
502: for (int i = 1; i < name.length(); i++) {
503: ch = name.charAt(i);
504: if (!(ch < 0x10000 && (CHARS[ch] & MASK_NAME) != 0)) {
505: return false;
506: }
507: }
508: return true;
509: }
510:
511: /* (non-Javadoc)
512: * @see org.w3c.dom.Element#getSchemaTypeInfo()
513: */
514: public TypeInfo getSchemaTypeInfo() {
515: // TODO Auto-generated method stub
516: return null;
517: }
518:
519: /* (non-Javadoc)
520: * @see org.w3c.dom.Element#setIdAttribute(java.lang.String, boolean)
521: */
522: public void setIdAttribute(String arg0, boolean arg1)
523: throws DOMException {
524: // TODO Auto-generated method stub
525:
526: }
527:
528: /* (non-Javadoc)
529: * @see org.w3c.dom.Element#setIdAttributeNS(java.lang.String, java.lang.String, boolean)
530: */
531: public void setIdAttributeNS(String arg0, String arg1, boolean arg2)
532: throws DOMException {
533: // TODO Auto-generated method stub
534:
535: }
536:
537: /* (non-Javadoc)
538: * @see org.w3c.dom.Element#setIdAttributeNode(org.w3c.dom.Attr, boolean)
539: */
540: public void setIdAttributeNode(Attr arg0, boolean arg1)
541: throws DOMException {
542: // TODO Auto-generated method stub
543:
544: }
545:
546: /* (non-Javadoc)
547: * @see org.w3c.dom.Node#getNamespaceURI()
548: */
549: public String getNamespaceURI() {
550: // TODO Auto-generated method stub
551: return null;
552: }
553:
554: /* (non-Javadoc)
555: * @see org.w3c.dom.Node#getBaseURI()
556: */
557: public String getBaseURI() {
558: // TODO Auto-generated method stub
559: return null;
560: }
561:
562: /* (non-Javadoc)
563: * @see org.w3c.dom.Node#compareDocumentPosition(org.w3c.dom.Node)
564: */
565: public short compareDocumentPosition(Node arg0) throws DOMException {
566: // TODO Auto-generated method stub
567: return 0;
568: }
569:
570: /* (non-Javadoc)
571: * @see org.w3c.dom.Node#getTextContent()
572: */
573: public String getTextContent() throws DOMException {
574: // TODO Auto-generated method stub
575: return null;
576: }
577:
578: /* (non-Javadoc)
579: * @see org.w3c.dom.Node#setTextContent(java.lang.String)
580: */
581: public void setTextContent(String arg0) throws DOMException {
582: // TODO Auto-generated method stub
583:
584: }
585:
586: /* (non-Javadoc)
587: * @see org.w3c.dom.Node#isSameNode(org.w3c.dom.Node)
588: */
589: public boolean isSameNode(Node arg0) {
590: // TODO Auto-generated method stub
591: return false;
592: }
593:
594: /* (non-Javadoc)
595: * @see org.w3c.dom.Node#lookupPrefix(java.lang.String)
596: */
597: public String lookupPrefix(String arg0) {
598: // TODO Auto-generated method stub
599: return null;
600: }
601:
602: /* (non-Javadoc)
603: * @see org.w3c.dom.Node#isDefaultNamespace(java.lang.String)
604: */
605: public boolean isDefaultNamespace(String arg0) {
606: // TODO Auto-generated method stub
607: return false;
608: }
609:
610: /* (non-Javadoc)
611: * @see org.w3c.dom.Node#lookupNamespaceURI(java.lang.String)
612: */
613: public String lookupNamespaceURI(String arg0) {
614: // TODO Auto-generated method stub
615: return null;
616: }
617:
618: /* (non-Javadoc)
619: * @see org.w3c.dom.Node#isEqualNode(org.w3c.dom.Node)
620: */
621: public boolean isEqualNode(Node arg0) {
622: // TODO Auto-generated method stub
623: return false;
624: }
625:
626: /* (non-Javadoc)
627: * @see org.w3c.dom.Node#getFeature(java.lang.String, java.lang.String)
628: */
629: public Object getFeature(String arg0, String arg1) {
630: // TODO Auto-generated method stub
631: return null;
632: }
633:
634: /* (non-Javadoc)
635: * @see org.w3c.dom.Node#setUserData(java.lang.String, java.lang.Object, org.w3c.dom.UserDataHandler)
636: */
637: public Object setUserData(String arg0, Object arg1,
638: UserDataHandler arg2) {
639: // TODO Auto-generated method stub
640: return null;
641: }
642:
643: /* (non-Javadoc)
644: * @see org.w3c.dom.Node#getUserData(java.lang.String)
645: */
646: public Object getUserData(String arg0) {
647: // TODO Auto-generated method stub
648: return null;
649: }
650: }
|