001: /*
002: * @(#)HashMapElement.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.DOMException;
015: import org.w3c.dom.Document;
016: import org.w3c.dom.Element;
017: import org.w3c.dom.Node;
018: import org.w3c.dom.NodeList;
019:
020: /**
021: * @author Tweety
022: *
023: * A class representing a node in a meta-data tree, which implements
024: * the <a href="../../../../api/org/w3c/dom/Element.html">
025: *
026: * <p> Namespaces are ignored in this implementation. The terms "tag
027: * name" and "node name" are always considered to be synonymous.
028: *
029: * @version 1.0
030: */
031: public class HashMapElement extends ElementImpl {
032:
033: /**
034: * All <code>Element<code> type children of this <code>Element<code>
035: */
036: protected HashMap children = null;
037:
038: /**
039: * Constructs an empty <code>HashMapElement</code>.
040: */
041: public HashMapElement() {
042: super ();
043: children = new HashMap();
044: }
045:
046: /**
047: * Constructs a <code>HashMapElement</code> from the given node,
048: * without creating entire children subtree.
049: *
050: * @param element, as a <code>HashMapElement</code>.
051: */
052: public HashMapElement(HashMapElement element) {
053: super (element);
054: children = element.children;
055: }
056:
057: /**
058: * Constructs an <code>HashMapElement</code> with the given
059: * document owner and node name.
060: *
061: * @param ownerDoc the document owner of the node, as a <code>Document</code>.
062: * @param nodeName the name of the node, as a <code>String</code>.
063: */
064: public HashMapElement(Document ownerDoc, String name) {
065: super (ownerDoc, name);
066: this .children = new HashMap();
067: }
068:
069: /**
070: * Constructs an <code>HashMapElement</code> with the given
071: * document owner, node name, node type and node value.
072: *
073: * @param ownerDoc the document owner of the node, as a <code>Document</code>.
074: * @param nodeName the name of the node, as a <code>String</code>.
075: * @param type the type of the node, as a <code>short</code>.
076: * @param value the value of the node, as a <code>String</code>.
077: */
078: protected HashMapElement(Document ownerDoc, String nodeName,
079: short type, String value) {
080: super (ownerDoc, nodeName, type, value);
081: }
082:
083: /**
084: * Constructs an <code>HashMapElement</code> from a given node
085: * (creates the children subtree too), as a <code>Node</code>
086: *
087: * @param node, as a <code>Node</code>.
088: */
089: public HashMapElement(Node node) {
090: this (node, true);
091: }
092:
093: /**
094: * Constructs an <code>HashMapElement</code> from a given node,
095: * as a <code>Node</code>, and deep as <code>boolean</code>.
096: *
097: * @param node, as a <code>Node</code>.
098: * @param deep if <code>true</code>, recursively clone the subtree
099: * under the specified node; if <code>false</code>, clone only the
100: * node itself.
101: */
102: public HashMapElement(Node node, boolean deep) {
103: super (node, false);
104: children = new HashMap();
105: if (deep)
106: initNodeImplChildren(node);
107: }
108:
109: /**
110: * Creates new instance of the HashMapElement class from the given <code>Node</code>.
111: *
112: * @param node, as a <code>Node</code>.
113: *
114: * @return new instance of the HashMapElement class.
115: */
116: protected Node newElementInstance(Node node) {
117: return new HashMapElement(node);
118: }
119:
120: /**
121: * Creates new instance of <code>HashMapElement</code> from a given document
122: * as a <code>Document</code>.
123: *
124: * @param document document.
125: *
126: * @return new <code>Element</code> node as a root of the <code>Document</code>.
127: */
128: public static Element newInstance(Document document) {
129: Node root = document.getDocumentElement();
130: return new HashMapElement(root);
131: }
132:
133: /**
134: * Inserts the node <code>newChild</code> before the existing
135: * child node <code>refChild</code>. If <code>refChild</code> is
136: * <code>null</code>, insert <code>newChild</code> at the end of
137: * the list of children.
138: *
139: * @param newChild the <code>Node</code> to insert.
140: * @param refChild the reference <code>Node</code>.
141: *
142: * @return the node being inserted.
143: *
144: * @exception IllegalArgumentException if <code>newChild</code> is
145: * <code>null</code>.
146: */
147: public Node insertBefore(Node newChild, Node refChild) {
148: super .insertBefore(newChild, refChild);
149:
150: if (newChild.getNodeType() == ELEMENT_NODE) {
151: HashMapElement newChildNode = (HashMapElement) newChild;
152:
153: List list = (List) children.get(newChildNode.getTagName());
154: if (list == null)
155: list = new ArrayList();
156: list.add(newChildNode);
157: children.put(newChildNode.getTagName(), list);
158: }
159: return newChild;
160: }
161:
162: /**
163: * Replaces the child node <code>oldChild</code> with
164: * <code>newChild</code> in the list of children, and returns the
165: * <code>oldChild</code> node.
166: *
167: * @param newChild the <code>Node</code> to insert.
168: * @param oldChild the <code>Node</code> to be replaced.
169: *
170: * @return the node replaced.
171: *
172: * @exception IllegalArgumentException if <code>newChild</code> is
173: * <code>null</code>.
174: */
175: public Node replaceChild(Node newChild, Node oldChild) {
176: super .replaceChild(newChild, oldChild);
177:
178: if (oldChild.getNodeType() == ELEMENT_NODE) {
179: HashMapElement oldChildNode = (HashMapElement) oldChild;
180: List list = (List) children.get(oldChildNode.getTagName());
181: if (list != null) {
182: int index = list.indexOf(oldChildNode);
183: if (index != -1)
184: list.remove(index);
185: if (list.size() == 0)
186: children.remove(oldChildNode.getTagName());
187: }
188: }
189: if (newChild.getNodeType() == ELEMENT_NODE) {
190: HashMapElement newChildNode = (HashMapElement) newChild;
191: List list = (List) children.get(newChildNode.getTagName());
192: if (list == null)
193: list = new ArrayList();
194: list.add(newChildNode);
195: children.put(newChildNode.getTagName(), list);
196: }
197:
198: return oldChild;
199: }
200:
201: /**
202: * Removes the child node indicated by <code>oldChild</code> from
203: * the list of children, and returns it.
204: *
205: * @param oldChild the <code>Node</code> to be removed.
206: *
207: * @return the node removed.
208: *
209: * @exception IllegalArgumentException if <code>oldChild</code> is
210: * <code>null</code>.
211: */
212: public Node removeChild(Node oldChild) {
213: super .removeChild(oldChild);
214:
215: if (oldChild.getNodeType() == ELEMENT_NODE) {
216: HashMapElement oldChildNode = (HashMapElement) oldChild;
217:
218: List list = (List) children.get(oldChildNode.getTagName());
219: if (list != null) {
220: int index = list.indexOf(oldChildNode);
221: if (index != -1)
222: list.remove(index);
223: if (list.size() == 0)
224: children.remove(oldChildNode.getTagName());
225: }
226: }
227: return oldChild;
228: }
229:
230: /**
231: * Returns a duplicate of this node. The duplicate node has no
232: * parent (<code>getParentNode</code> returns <code>null</code>).
233: * If a shallow clone is being performed (<code>deep</code> is
234: * <code>false</code>), the new node will not have any children or
235: * siblings. If a deep clone is being performed, the new node
236: * will form the root of a complete cloned subtree.
237: *
238: * @param deep if <code>true</code>, recursively clone the subtree
239: * under the specified node; if <code>false</code>, clone only the
240: * node itself.
241: *
242: * @return the duplicate node.
243: */
244: public Node cloneNode(boolean deep) {
245: return new HashMapElement(this , deep);
246: }
247:
248: /**
249: * Returns all <code>Element</code> nodes with given name,
250: * searching by all sub nodes from this node.
251: *
252: * @param name tag name.
253: *
254: * @return all <code>Element</code> vith given name as <code>NodeList</code>.
255: */
256: public NodeList getElementsByTagName(String name) {
257: List list = new ArrayList();
258:
259: // added for new search
260: if (nodeName.equals(name)) {
261: list.add(this );
262: }
263:
264: getElementsByTagName(name, list);
265: return new NodeListImpl(list);
266: }
267:
268: private void getElementsByTagName(String name, List list) {
269: if (numChildren == 0)
270: return;
271: List fList = (List) children.get(name);
272: if (fList != null)
273: ;
274: list.addAll(fList);
275: for (Iterator iter = children.values().iterator(); iter
276: .hasNext();) {
277: fList = (List) iter.next();
278: for (int i = 0; i < fList.size(); i++) {
279: ((HashMapElement) fList.get(i)).getElementsByTagName(
280: name, list);
281: }
282: }
283: }
284:
285: /**
286: * Returns <code>true</code> if this node has child nodes.
287: *
288: * @return <code>true</code> if this node has children.
289: */
290: public boolean hasElementChildNodes() {
291: return children.size() > 0;
292: }
293:
294: /**
295: * Returns the list of all children nodes with the given tag name.
296: *
297: * @param name tag name.
298: *
299: * @return the list of all children nodes with the given tag name.
300: */
301: public NodeList getChildrenByTagName(String name) {
302: List list = (List) this .children.get(name);
303: if (list != null)
304: return new NodeListImpl(list);
305: return null;
306: }
307:
308: /**
309: * Returns the first child <code>Element</code> with the given tag name.
310: *
311: * @param name tag name.
312: *
313: * @return the first child <code>Element</code> with the given tag name.
314: */
315: public Element getFirstChildByTagName(String name) {
316: NodeList children = getChildrenByTagName(name);
317: if (children != null && children.getLength() > 0)
318: return (HashMapElement) children.item(0);
319: return null;
320: }
321:
322: /**
323: * Returns the next <code>Element</code> node (if exists) with the same tag name.
324: *
325: * @return the next <code>Element</code> node (if exists) with the same tag name.
326: */
327: public Element getNextSameNameNode() {
328: try {
329: HashMapElement parent = (HashMapElement) this
330: .getParentNode();
331: List tagList = (List) parent.children.get(this .nodeName);
332: int index = tagList.indexOf(this );
333: if (++index <= tagList.size())
334: return (HashMapElement) tagList.get(index);
335: } catch (NullPointerException e) {
336: throw new NodeDOMException(DOMException.NOT_FOUND_ERR,
337: "Root node doesn't have a successor");
338: }
339: return null;
340: }
341:
342: /**
343: * Returns the concatenation of values of all text type children.
344: *
345: * @return the concatenation of values of all text type children.
346: */
347: public String getText() {
348: StringBuffer textBuffer = new StringBuffer("");
349: Node child = this .getFirstChild();
350: while (child != null) {
351: if (child.getNodeType() == Node.TEXT_NODE)
352: textBuffer.append(child.getNodeValue());
353: child = child.getNextSibling();
354: }
355: if (!textBuffer.toString().equals(""))
356: return textBuffer.toString();
357: return null;
358: }
359:
360: /**
361: * Set the value of the first text child node to the given text,
362: * and remove all other text child nodes.
363: *
364: * @param text new text.
365: */
366: public void setText(String text) {
367: Node child = this .getFirstChild();
368: if (child != null) {
369: child.setNodeValue(text);
370: child = child.getNextSibling();
371: while (child != null) {
372: if (child.getNodeType() == Node.TEXT_NODE) {
373: Node temp = child;
374: child = child.getNextSibling();
375: this.removeChild(temp);
376: } else {
377: child = child.getNextSibling();
378: }
379: }
380: }
381: }
382:
383: }
|