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