1 /*
2 * @(#)ElementImpl.java 1.36 02/03/21
3 *
4 * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
5 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6 */
7 package org.enhydra.xml;
8
9 import java.io.File;
10 import java.io.FileOutputStream;
11 import java.util.ArrayList;
12 import java.util.Iterator;
13 import java.util.List;
14 import java.util.HashMap;
15 import java.util.HashMap;
16
17 import org.w3c.dom.Attr;
18 import org.w3c.dom.Document;
19 import org.w3c.dom.Element;
20 import org.w3c.dom.DOMException;
21 import org.w3c.dom.NamedNodeMap;
22 import org.w3c.dom.Node;
23 import org.w3c.dom.NodeList;
24
25 /***
26 * @author Tweety
27 *
28 * A class representing a node in a meta-data tree, which implements
29 * the <a href="../../../../api/org/w3c/dom/Element.html">
30 *
31 * <p> Namespaces are ignored in this implementation. The terms "tag
32 * name" and "node name" are always considered to be synonymous.
33 *
34 * @version 1.0
35 */
36 public class ElementImpl extends NodeImpl implements Element {
37
38 /***
39 * A <code>HashMap</code> of <code>AttrImpl</code> nodes representing
40 * attributes.
41 */
42 protected HashMap attributes = null;
43
44
45 /***
46 * Constructs an empty <code>ElementImpl</code>.
47 */
48 public ElementImpl() {
49 attributes = new HashMap();
50 type = ELEMENT_NODE;
51 }
52
53
54 /***
55 * Constructs a <code>ElementImpl</code> from the given node,
56 * without creating entire children subtree.
57 *
58 * @param element, as a <code>ElementImpl</code>.
59 */
60 public ElementImpl(ElementImpl element) {
61 super(element);
62 attributes = element.attributes;
63 type = ELEMENT_NODE;
64 }
65
66
67 /***
68 * Constructs an <code>ElementImpl</code> with the given
69 * document owner and node name.
70 *
71 * @param ownerDoc the document owner of the node, as a <code>Document</code>.
72 * @param nodeName the name of the node, as a <code>String</code>.
73 */
74 public ElementImpl(Document ownerDoc, String name) {
75 super(ownerDoc,name,ELEMENT_NODE);
76 this.attributes = new HashMap();
77 }
78
79
80 /***
81 * Constructs an <code>ElementImpl</code> with the given
82 * document owner, node name, node type and node value.
83 *
84 * @param ownerDoc the document owner of the node, as a <code>Document</code>.
85 * @param nodeName the name of the node, as a <code>String</code>.
86 * @param type the type of the node, as a <code>short</code>.
87 * @param value the value of the node, as a <code>String</code>.
88 */
89 protected ElementImpl(Document ownerDoc, String nodeName, short type, String value) {
90 super(ownerDoc, nodeName, type, value);
91 }
92
93
94 /***
95 * Constructs an <code>ElementImpl</code> from a given node (creates the children subtree too),
96 * as a <code>Node</code>
97 *
98 * @param node, as a <code>Node</code>.
99 */
100 public ElementImpl(Node node) {
101 this(node,true);
102 }
103
104
105 /***
106 * Constructs an <code>ElementImpl</code> from a given node, as a <code>Node</code>,
107 * and deep as <code>boolean</code>.
108 *
109 * @param node, as a <code>Node</code>.
110 * @param deep if <code>true</code>, recursively clone the subtree
111 * under the specified node; if <code>false</code>, clone only the
112 * node itself.
113 */
114 public ElementImpl(Node node, boolean deep) {
115 super(node,false);
116 attributes = new HashMap();
117 NamedNodeMap attrs = node.getAttributes();
118 if (attrs != null) {
119 for (int i = 0; i < attrs.getLength(); i++) {
120 Attr attr = new AttrImpl((Attr) attrs.item(i));
121 attributes.put(attr.getName(), attr);
122 }
123 }
124 if (deep)
125 initNodeImplChildren(node);
126 }
127
128
129 /***
130 * Creates new instance of <code>ElementImpl</code> from a given document
131 * as a <code>Document</code>.
132 *
133 * @param document document.
134 *
135 * @return new <code>Element</code> node as a root of the <code>Document</code>.
136 */
137 public static Element newInstance(Document document) {
138 Node root = document.getDocumentElement();
139 return new ElementImpl(root);
140 }
141
142
143 /***
144 * Inserts the node <code>newChild</code> before the existing
145 * child node <code>refChild</code>. If <code>refChild</code> is
146 * <code>null</code>, insert <code>newChild</code> at the end of
147 * the list of children.
148 *
149 * @param newChild the <code>Node</code> to insert.
150 * @param refChild the reference <code>Node</code>.
151 *
152 * @return the node being inserted.
153 *
154 * @exception IllegalArgumentException if <code>newChild</code> is
155 * <code>null</code>.
156 */
157 public Node insertBefore(Node newChild, Node refChild) {
158 super.insertBefore(newChild,refChild);
159 return newChild;
160 }
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 /***
183 * Removes the child node indicated by <code>oldChild</code> from
184 * the list of children, and returns it.
185 *
186 * @param oldChild the <code>Node</code> to be removed.
187 *
188 * @return the node removed.
189 *
190 * @exception IllegalArgumentException if <code>oldChild</code> is
191 * <code>null</code>.
192 */
193 public Node removeChild(Node oldChild) {
194 super.removeChild(oldChild);
195 return oldChild;
196 }
197
198
199 /***
200 * Returns a duplicate of this node. The duplicate node has no
201 * parent (<code>getParentNode</code> returns <code>null</code>).
202 * If a shallow clone is being performed (<code>deep</code> is
203 * <code>false</code>), the new node will not have any children or
204 * siblings. If a deep clone is being performed, the new node
205 * will form the root of a complete cloned subtree.
206 *
207 * @param deep if <code>true</code>, recursively clone the subtree
208 * under the specified node; if <code>false</code>, clone only the
209 * node itself.
210 *
211 * @return the duplicate node.
212 */
213 public Node cloneNode(boolean deep) {
214 return new ElementImpl(this,deep);
215 }
216
217
218
219
220
221 // Methods from Element
222
223
224 /***
225 * Returns tag name of this node.
226 *
227 * @return tag name of this node as a <code>String</code>.
228 */
229 public String getTagName() {
230 return nodeName;
231 }
232
233
234 /***
235 * Returns all attribute nodes of this node.
236 *
237 * @return all attribute nodes of this node as a <code>NamedNodeMap</code>.
238 */
239 public NamedNodeMap getAttributes() {
240 return new HashMapNamedNodeMap(attributes);
241 }
242
243
244 /***
245 * Returns the value of the attribute with given name.
246 *
247 * @param name name of attribute.
248 *
249 * @return value of attribute.
250 */
251 public String getAttribute(String name) {
252 Attr attr = getAttributeNode(name);
253 if (attr == null) {
254 return "";
255 }
256 return attr.getValue();
257 }
258
259
260 /***
261 * Equivalent to <code>getAttribute(localName)</code>.
262 *
263 * @see #setAttributeNS
264 */
265 public String getAttributeNS(String namespaceURI, String localName) {
266 return getAttribute(localName);
267 }
268
269
270 /***
271 * To the <code>name</code> attribute set value to <code>value</code>.
272 *
273 * @param name attribute value.
274 * @param value new attribute value.
275 */
276 public void setAttribute(String name, String value) {
277 // Note minor dependency on Crimson package
278 // Steal the code if Crimson ever goes away
279 if (!org.apache.crimson.util.XmlNames.isName(name)) {
280 throw new NodeDOMException(
281 DOMException.INVALID_CHARACTER_ERR,
282 "Attribute name is illegal!");
283 }
284 attributes.put(name, new AttrImpl(this, name, value));
285 }
286
287
288 /***
289 * Equivalent to <code>setAttribute(qualifiedName, value)</code>.
290 *
291 * @see #getAttributeNS
292 */
293 public void setAttributeNS(String namespaceURI, String qualifiedName, String value) {
294 setAttribute(qualifiedName, value);
295 }
296
297
298 /***
299 * Removes attribute with the given name.
300 *
301 * @param name attribute name.
302 */
303 public void removeAttribute(String name) {
304 if (type != ELEMENT_NODE)
305 throw new NodeDOMException(
306 DOMException.NOT_SUPPORTED_ERR,
307 "Node doesn't have attributes");
308 removeAttribute(name, true);
309 }
310
311
312 private void removeAttribute(String name, boolean checkPresent) {
313 if (attributes.remove(name) != null)
314 return;
315 // If we get here, the attribute doesn't exist
316 if (checkPresent) {
317 throw new NodeDOMException(
318 DOMException.NOT_FOUND_ERR,
319 "No such attribute!");
320 }
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 /***
336 * Returns <code>true</code>, if this node has attribute with given name,
337 * otherwise <code>false</code>.
338 *
339 * @return <code>true</code> if node has given attribute, otherwise <code>false</code>..
340 */
341 public boolean hasAttribute(String name) {
342 return getAttributeNode(name) != null;
343 }
344
345
346 /***
347 * Equivalent to <code>removeAttribute(localName)</code>.
348 */
349 public void removeAttributeNS(String namespaceURI, String localName) {
350 removeAttribute(localName);
351 }
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 /***
367 * Equivalent to <code>getAttributeNode(localName)</code>.
368 *
369 * @see #setAttributeNodeNS
370 */
371 public Attr getAttributeNodeNS(String namespaceURI, String localName) {
372 return getAttributeNode(localName);
373 }
374
375
376 /***
377 * Add new attribute to this node.
378 *
379 * @param newAttr new attribute.
380 *
381 * @return new attribute as <code>AttrImpl</code>.
382 */
383 public Attr setAttributeNode(Attr newAttr) throws DOMException {
384 AttrImpl attr;
385 if (newAttr instanceof AttrImpl) {
386 attr = (AttrImpl) newAttr;
387 } else {
388 attr = new AttrImpl(newAttr);
389 }
390 attributes.put(attr.getName(), attr);
391 return attr;
392 }
393
394
395 /***
396 * Equivalent to <code>setAttributeNode(newAttr)</code>.
397 *
398 * @see #getAttributeNodeNS
399 */
400 public Attr setAttributeNodeNS(Attr newAttr) {
401 return setAttributeNode(newAttr);
402 }
403
404
405 /***
406 * Remove attribute from this node.
407 *
408 * @param oldAttr attribute that will be removed.
409 *
410 * @return old attribute as <code>AttrImpl</code>.
411 */
412 public Attr removeAttributeNode(Attr oldAttr) {
413 removeAttribute(oldAttr.getName());
414 return oldAttr;
415 }
416
417
418 /***
419 * Equivalent to <code>hasAttribute(localName)</code>.
420 */
421 public boolean hasAttributeNS(String namespaceURI, String localName) {
422 return hasAttribute(localName);
423 }
424
425
426 /***
427 * Returns all <code>Element</code> nodes with given name,
428 * searching by all sub nodes from this node.
429 *
430 * @param name tag name.
431 *
432 * @return all <code>Element</code> vith given name as <code>NodeList</code>.
433 */
434 public NodeList getElementsByTagName(String name) {
435 List list = new ArrayList();
436 getElementsByTagName(name, list);
437 return new NodeListImpl(list);
438 }
439
440
441 private void getElementsByTagName(String name, List list) {
442 if (nodeName.equals(name)) {
443 list.add(this);
444 }
445
446 Node child = getFirstChild();
447 while (child != null) {
448 if (child.getNodeType() == Node.ELEMENT_NODE)
449 ((ElementImpl)child).getElementsByTagName(name, list);
450 child = child.getNextSibling();
451 }
452 }
453
454
455 /***
456 * Equivalent to <code>getElementsByTagName(localName)</code>.
457 */
458 public NodeList getElementsByTagNameNS(String namespaceURI, String localName) {
459 return getElementsByTagName(localName);
460 }
461
462
463 /***
464 * Returns <code>true</code> if this node has children nodes.
465 *
466 * @return <code>true</code> if this node has children.
467 */
468 public boolean hasElementChildNodes() {
469 Node child = getFirstChild();
470 while (child != null) {
471 if (child.getNodeType() == Node.ELEMENT_NODE)
472 return true;
473 child = child.getNextSibling();
474 }
475 return false;
476 }
477
478
479 /***
480 * Method beginToString for this class writes the xml
481 * begining tag string and all attributes.
482 *
483 * @param sb string buffer to add resulting string.
484 * @param indent used in formating the output.
485 */
486 protected void beginToString(StringBuffer sb, Indent indent) {
487 sb.append("\n" + indent + "<" + this.nodeName);
488
489 for (Iterator iter = attributes.values().iterator(); iter.hasNext();) {
490 Attr attr = (Attr) iter.next();
491 sb.append(" " + attr.getNodeName() + "=\"" + attr.getNodeValue() + "\"");
492 }
493 // if (hasChildNodes()) {
494 sb.append(">");
495 indent.increment();
496 // } else
497 // sb.append("/>");
498 }
499
500
501 /***
502 * Method endToString for this class writes the xml
503 * ending tag string.
504 *
505 * @param sb string buffer to add resulting string.
506 * @param indent used in formating the output.
507 */
508 protected void endToString(StringBuffer sb, Indent indent) {
509 // if (hasChildNodes()) {
510 indent.decrement();
511 if (hasElementChildNodes())
512 sb.append("\n" + indent + "</" + this.nodeName + ">");
513 else
514 sb.append("</" + this.nodeName + ">");
515 // }
516 }
517 }
This page automatically generated by Maven