001: /* XMLElement.java NanoXML/Java
002: *
003: * $Revision: 2056 $
004: * $Date: 2008-02-25 00:29:28 -0800 (Mon, 25 Feb 2008) $
005: * $Name$
006: *
007: * This file is part of NanoXML 2 for Java.
008: * Copyright (C) 2001 Marc De Scheemaecker, All Rights Reserved.
009: *
010: * This software is provided 'as-is', without any express or implied warranty.
011: * In no event will the authors be held liable for any damages arising from the
012: * use of this software.
013: *
014: * Permission is granted to anyone to use this software for any purpose,
015: * including commercial applications, and to alter it and redistribute it
016: * freely, subject to the following restrictions:
017: *
018: * 1. The origin of this software must not be misrepresented; you must not
019: * claim that you wrote the original software. If you use this software in
020: * a product, an acknowledgment in the product documentation would be
021: * appreciated but is not required.
022: *
023: * 2. Altered source versions must be plainly marked as such, and must not be
024: * misrepresented as being the original software.
025: *
026: * 3. This notice may not be removed or altered from any source distribution.
027: */
028:
029: package net.n3.nanoxml;
030:
031: import java.io.Serializable;
032: import java.util.Enumeration;
033: import java.util.Properties;
034: import java.util.Vector;
035:
036: /**
037: * XMLElement is an XML element. The standard NanoXML builder generates a tree of such elements.
038: *
039: * @see net.n3.nanoxml.StdXMLBuilder
040: *
041: * @author Marc De Scheemaecker
042: * @version $Name$, $Revision: 2056 $
043: */
044: public class XMLElement implements Serializable {
045:
046: /**
047: * Necessary for serialization.
048: */
049: static final long serialVersionUID = -2383376380548624920L;
050:
051: /**
052: * No line number defined.
053: */
054: public static final int NO_LINE = -1;
055:
056: /**
057: * The attributes of the element.
058: */
059: private Properties attributes;
060:
061: /**
062: * The child elements.
063: */
064: private Vector children;
065:
066: /**
067: * The name of the element.
068: */
069: private String name;
070:
071: /**
072: * The content of the element.
073: */
074: private String content;
075:
076: /**
077: * The system ID of the source data where this element is located.
078: */
079: private String systemID;
080:
081: /**
082: * The line in the source data where this element starts.
083: */
084: private int lineNr;
085:
086: /**
087: * Creates an empty element to be used for #PCDATA content.
088: */
089: public XMLElement() {
090: this (null, null, NO_LINE);
091: }
092:
093: /**
094: * Creates an empty element.
095: *
096: * @param name the name of the element.
097: */
098: public XMLElement(String name) {
099: this (name, null, NO_LINE);
100: }
101:
102: /**
103: * Creates an empty element.
104: *
105: * @param name the name of the element.
106: * @param systemID the system ID of the XML data where the element starts.
107: * @param lineNr the line in the XML data where the element starts.
108: */
109: public XMLElement(String name, String systemID, int lineNr) {
110: this .attributes = new Properties();
111: this .children = new Vector(8);
112: this .name = name;
113: this .content = null;
114: this .lineNr = lineNr;
115: this .systemID = systemID;
116: }
117:
118: /**
119: * Cleans up the object when it's destroyed.
120: */
121: protected void finalize() throws Throwable {
122: this .attributes = null;
123: this .children = null;
124: this .name = null;
125: this .content = null;
126: this .systemID = null;
127: super .finalize();
128: }
129:
130: /**
131: * Returns the name of the element.
132: *
133: * @return the name, or null if the element only contains #PCDATA.
134: */
135: public String getName() {
136: return this .name;
137: }
138:
139: /**
140: * Sets the name.
141: *
142: * @param name the non-null name.
143: */
144: public void setName(String name) {
145: if (name == null) {
146: throw new IllegalArgumentException("name must not be null");
147: }
148:
149: this .name = name;
150: }
151:
152: /**
153: * Adds a child element.
154: *
155: * @param child the non-null child to add.
156: */
157: public void addChild(XMLElement child) {
158: if (child == null) {
159: throw new IllegalArgumentException("child must not be null");
160: }
161:
162: if ((child.getName() == null) && (!this .children.isEmpty())) {
163: XMLElement lastChild = (XMLElement) this .children
164: .lastElement();
165:
166: if (lastChild.getName() == null) {
167: lastChild.setContent(lastChild.getContent()
168: + child.getContent());
169: return;
170: }
171: }
172:
173: this .children.addElement(child);
174: }
175:
176: /**
177: * Removes a child element.
178: *
179: * @param child the non-null child to remove.
180: */
181: public void removeChild(XMLElement child) {
182: if (child == null) {
183: throw new IllegalArgumentException("child must not be null");
184: }
185:
186: this .children.removeElement(child);
187: }
188:
189: /**
190: * Removes the child located at a certain index.
191: *
192: * @param index the index of the child, where the first child has index 0.
193: */
194: public void removeChildAtIndex(int index) {
195: this .children.removeElementAt(index);
196: }
197:
198: /**
199: * Returns an enumeration of all child elements.
200: *
201: * @return the non-null enumeration
202: */
203: public Enumeration enumerateChildren() {
204: return this .children.elements();
205: }
206:
207: /**
208: * Returns whether the element is a leaf element.
209: *
210: * @return true if the element has no children.
211: */
212: public boolean isLeaf() {
213: return this .children.isEmpty();
214: }
215:
216: /**
217: * Returns whether the element has children.
218: *
219: * @return true if the element has children.
220: */
221: public boolean hasChildren() {
222: return (!this .children.isEmpty());
223: }
224:
225: /**
226: * Returns the number of children.
227: *
228: * @return the count.
229: */
230: public int getChildrenCount() {
231: return this .children.size();
232: }
233:
234: /**
235: * Returns a vector containing all the child elements.
236: *
237: * @return the vector.
238: */
239: public Vector getChildren() {
240: return this .children;
241: }
242:
243: /**
244: * Returns the child at a specific index.
245: *
246: * @return the non-null child
247: *
248: * @throws java.lang.ArrayIndexOutOfBoundsException if the index is out of bounds.
249: */
250: public XMLElement getChildAtIndex(int index)
251: throws ArrayIndexOutOfBoundsException {
252: return (XMLElement) this .children.elementAt(index);
253: }
254:
255: /**
256: * Searches a child element.
257: *
258: * @param name the name of the child to search for.
259: *
260: * @return the child element, or null if no such child was found.
261: */
262: public XMLElement getFirstChildNamed(String name) {
263: Enumeration enumeration = this .children.elements();
264:
265: while (enumeration.hasMoreElements()) {
266: XMLElement child = (XMLElement) enumeration.nextElement();
267: String cName = child.getName();
268:
269: if (cName != null && cName.equals(name)) {
270: return child;
271: }
272: }
273:
274: return null;
275: }
276:
277: /**
278: * Returns a vector of all child elements named <I>name</I>.
279: *
280: * @param name the name of the children to search for.
281: *
282: * @return the non-null vector of child elements.
283: */
284: public Vector<XMLElement> getChildrenNamed(String name) {
285: Vector<XMLElement> result = new Vector<XMLElement>(
286: this .children.size());
287: Enumeration enumeration = this .children.elements();
288:
289: while (enumeration.hasMoreElements()) {
290: XMLElement child = (XMLElement) enumeration.nextElement();
291: String cName = child.getName();
292:
293: if (cName != null && cName.equals(name)) {
294: result.addElement(child);
295: }
296: }
297:
298: return result;
299: }
300:
301: /**
302: * Returns the value of an attribute.
303: *
304: * @param name the non-null name of the attribute.
305: *
306: * @return the value, or null if the attribute does not exist.
307: */
308: public String getAttribute(String name) {
309: return this .getAttribute(name, null);
310: }
311:
312: /**
313: * Returns the value of an attribute.
314: *
315: * @param name the non-null name of the attribute.
316: * @param defaultValue the default value of the attribute.
317: *
318: * @return the value, or defaultValue if the attribute does not exist.
319: */
320: public String getAttribute(String name, String defaultValue) {
321: return this .attributes.getProperty(name, defaultValue);
322: }
323:
324: /**
325: * Sets an attribute.
326: *
327: * @param name the non-null name of the attribute.
328: * @param value the non-null value of the attribute.
329: */
330: public void setAttribute(String name, String value) {
331: this .attributes.put(name, value);
332: }
333:
334: /**
335: * Removes an attribute.
336: *
337: * @param name the non-null name of the attribute.
338: */
339: public void removeAttribute(String name) {
340: this .attributes.remove(name);
341: }
342:
343: /**
344: * Returns an enumeration of all attribute names.
345: *
346: * @return the non-null enumeration.
347: */
348: public Enumeration enumerateAttributeNames() {
349: return this .attributes.keys();
350: }
351:
352: /**
353: * Returns whether an attribute exists.
354: *
355: * @return true if the attribute exists.
356: */
357: public boolean hasAttribute(String name) {
358: return this .attributes.containsKey(name);
359: }
360:
361: /**
362: * Returns all attributes as a Properties object.
363: *
364: * @return the non-null set.
365: */
366: public Properties getAttributes() {
367: return this .attributes;
368: }
369:
370: /**
371: * Returns the system ID of the data where the element started.
372: *
373: * @return the system ID, or null if unknown.
374: *
375: * @see #getLineNr
376: */
377: public String getSystemID() {
378: return this .systemID;
379: }
380:
381: /**
382: * Returns the line number in the data where the element started.
383: *
384: * @return the line number, or NO_LINE if unknown.
385: *
386: * @see #NO_LINE
387: * @see #getSystemID
388: */
389: public int getLineNr() {
390: return this .lineNr;
391: }
392:
393: /**
394: * Return the #PCDATA content of the element. If the element has a combination of #PCDATA
395: * content and child elements, the #PCDATA sections can be retrieved as unnamed child objects.
396: * In this case, this method returns null.
397: *
398: * @return the content.
399: */
400: public String getContent() {
401: return this .content;
402: }
403:
404: /**
405: * Sets the #PCDATA content. It is an error to call this method with a non-null value if there
406: * are child objects.
407: *
408: * @param content the (possibly null) content.
409: */
410: public void setContent(String content) {
411: this.content = content;
412: }
413:
414: }
|