c49f555c56c8f3a8c8124242f6a1dea68a7a829c
[jSite.git] / src / de / todesbaum / util / xml / SimpleXML.java
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15  */
16
17 package de.todesbaum.util.xml;
18
19 import java.util.ArrayList;
20 import java.util.List;
21
22 import javax.xml.parsers.DocumentBuilder;
23 import javax.xml.parsers.DocumentBuilderFactory;
24 import javax.xml.parsers.ParserConfigurationException;
25
26 import org.w3c.dom.Document;
27 import org.w3c.dom.Element;
28 import org.w3c.dom.Node;
29 import org.w3c.dom.NodeList;
30 import org.w3c.dom.Text;
31
32 /**
33  * SimpleXML is a helper class to construct XML trees in a fast and simple way.
34  * Construct a new XML tree by calling {@link #SimpleXML(String)} and append new
35  * nodes by calling {@link #append(String)}.
36  *
37  * @author David Roden <droden@gmail.com>
38  * @version $Id:SimpleXML.java 221 2006-03-06 14:46:49Z bombe $
39  */
40 public class SimpleXML {
41
42         /**
43          * A {@link List} containing all child nodes of this node.
44          */
45         private List<SimpleXML> children = new ArrayList<SimpleXML>();
46
47         /**
48          * The name of this node.
49          */
50         private String name = null;
51
52         /**
53          * The value of this node.
54          */
55         private String value = null;
56
57         /**
58          * Constructs a new XML node without a name.
59          */
60         public SimpleXML() {
61                 super();
62         }
63
64         /**
65          * Constructs a new XML node with the specified name.
66          *
67          * @param name
68          *            The name of the new node
69          */
70         public SimpleXML(String name) {
71                 this.name = name;
72         }
73
74         /**
75          * Returns the child node of this node with the specified name. If there are
76          * several child nodes with the specified name only the first node is
77          * returned.
78          *
79          * @param nodeName
80          *            The name of the child node
81          * @return The child node, or <code>null</code> if there is no child node
82          *         with the specified name
83          */
84         public SimpleXML getNode(String nodeName) {
85                 for (int index = 0, count = children.size(); index < count; index++) {
86                         if (children.get(index).name.equals(nodeName)) {
87                                 return children.get(index);
88                         }
89                 }
90                 return null;
91         }
92
93         /**
94          * Returns the child node that is specified by the names. The first element
95          * of <code>nodeNames</code> is the name of the child node of this node, the
96          * second element of <code>nodeNames</code> is the name of a child node's
97          * child node, and so on. By using this method you can descend into an XML
98          * tree pretty fast.
99          *
100          * <pre>
101          *
102          * SimpleXML deepNode = topNode.getNodes(new String[] { &quot;person&quot;, &quot;address&quot;, &quot;number&quot; });
103          * </pre>
104          *
105          * @param nodeNames
106          * @return A node that is a deep child of this node, or <code>null</code> if
107          *         the specified node does not eixst
108          */
109         public SimpleXML getNode(String[] nodeNames) {
110                 SimpleXML node = this;
111                 for (String nodeName : nodeNames) {
112                         node = node.getNode(nodeName);
113                 }
114                 return node;
115         }
116
117         /**
118          * Returns all child nodes of this node.
119          *
120          * @return All child nodes of this node
121          */
122         public SimpleXML[] getNodes() {
123                 return getNodes(null);
124         }
125
126         /**
127          * Returns all child nodes of this node with the specified name. If there
128          * are no child nodes with the specified name an empty array is returned.
129          *
130          * @param nodeName
131          *            The name of the nodes to retrieve, or <code>null</code> to
132          *            retrieve all nodes
133          * @return All child nodes with the specified name
134          */
135         public SimpleXML[] getNodes(String nodeName) {
136                 List<SimpleXML> resultList = new ArrayList<SimpleXML>();
137                 for (SimpleXML child : children) {
138                         if ((nodeName == null) || child.name.equals(nodeName)) {
139                                 resultList.add(child);
140                         }
141                 }
142                 return resultList.toArray(new SimpleXML[resultList.size()]);
143         }
144
145         /**
146          * Appends a new XML node with the specified name and returns the new node.
147          * With this method you can create deep structures very fast.
148          *
149          * <pre>
150          *
151          * SimpleXML mouseNode = topNode.append(&quot;computer&quot;).append(&quot;bus&quot;).append(&quot;usb&quot;).append(&quot;mouse&quot;);
152          * </pre>
153          *
154          * @param nodeName
155          *            The name of the node to append as a child to this node
156          * @return The new node
157          */
158         public SimpleXML append(String nodeName) {
159                 return append(new SimpleXML(nodeName));
160         }
161
162         /**
163          * Appends a new XML node with the specified name and value and returns the
164          * new node.
165          *
166          * @param nodeName
167          *            The name of the node to append
168          * @param nodeValue
169          *            The value of the node to append
170          * @return The newly appended node
171          */
172         public SimpleXML append(String nodeName, String nodeValue) {
173                 return append(nodeName).setValue(nodeValue);
174         }
175
176         /**
177          * Appends the node with all its child nodes to this node and returns the
178          * child node.
179          *
180          * @param newChild
181          *            The node to append as a child
182          * @return The child node that was appended
183          */
184         public SimpleXML append(SimpleXML newChild) {
185                 children.add(newChild);
186                 return newChild;
187         }
188
189         public void remove(SimpleXML child) {
190                 children.remove(child);
191         }
192
193         public void remove(String childName) {
194                 SimpleXML child = getNode(childName);
195                 if (child != null) {
196                         remove(child);
197                 }
198         }
199
200         public void replace(String childName, String value) {
201                 remove(childName);
202                 append(childName, value);
203         }
204
205         public void replace(SimpleXML childNode) {
206                 remove(childNode.getName());
207                 append(childNode);
208         }
209
210         public void removeAll() {
211                 children.clear();
212         }
213
214         /**
215          * Sets the value of this node.
216          *
217          * @param nodeValue
218          *            The new value of this node
219          * @return This node
220          */
221         public SimpleXML setValue(String nodeValue) {
222                 value = nodeValue;
223                 return this;
224         }
225
226         /**
227          * Returns the name of this node.
228          *
229          * @return The name of this node
230          */
231         public String getName() {
232                 return name;
233         }
234
235         /**
236          * Returns the value of this node.
237          *
238          * @return The value of this node
239          */
240         public String getValue() {
241                 return value;
242         }
243
244         /**
245          * Returns the value of this node. If the node does not have a value, the
246          * given default value is returned.
247          *
248          *@param defaultValue
249          *            The default value to return if the node does not have a value
250          * @return The value of this node
251          */
252         public String getValue(String defaultValue) {
253                 return (value == null) ? defaultValue : value;
254         }
255
256         /**
257          * Creates a {@link Document} from this node and all its child nodes.
258          *
259          * @return The {@link Document} created from this node
260          */
261         public Document getDocument() {
262                 DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
263                 try {
264                         DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
265                         Document document = documentBuilder.newDocument();
266                         Element rootElement = document.createElement(name);
267                         document.appendChild(rootElement);
268                         addChildren(rootElement);
269                         return document;
270                 } catch (ParserConfigurationException e) {
271                 }
272                 return null;
273         }
274
275         /**
276          * Appends all children of this node to the specified {@link Element}. If a
277          * node has a value that is not <code>null</code> the value is appended as a
278          * text node.
279          *
280          * @param rootElement
281          *            The element to attach this node's children to
282          */
283         private void addChildren(Element rootElement) {
284                 for (SimpleXML child : children) {
285                         Element childElement = rootElement.getOwnerDocument().createElement(child.name);
286                         rootElement.appendChild(childElement);
287                         if (child.value != null) {
288                                 Text childText = rootElement.getOwnerDocument().createTextNode(child.value);
289                                 childElement.appendChild(childText);
290                         } else {
291                                 child.addChildren(childElement);
292                         }
293                 }
294         }
295
296         /**
297          * Creates a SimpleXML node from the specified {@link Document}. The
298          * SimpleXML node of the document's top-level node is returned.
299          *
300          * @param document
301          *            The {@link Document} to create a SimpleXML node from
302          * @return The SimpleXML node created from the document's top-level node
303          */
304         public static SimpleXML fromDocument(Document document) {
305                 SimpleXML xmlDocument = new SimpleXML(document.getFirstChild().getNodeName());
306                 document.normalizeDocument();
307                 return addDocumentChildren(xmlDocument, document.getFirstChild());
308         }
309
310         /**
311          * Appends the child nodes of the specified {@link Document} to this node.
312          * Text nodes are converted into a node's value.
313          *
314          * @param xmlDocument
315          *            The SimpleXML node to append the child nodes to
316          * @param document
317          *            The document whose child nodes to append
318          * @return The SimpleXML node the child nodes were appended to
319          */
320         private static SimpleXML addDocumentChildren(SimpleXML xmlDocument, Node document) {
321                 NodeList childNodes = document.getChildNodes();
322                 for (int childIndex = 0, childCount = childNodes.getLength(); childIndex < childCount; childIndex++) {
323                         Node childNode = childNodes.item(childIndex);
324                         if ((childNode.getChildNodes().getLength() == 1) && (childNode.getFirstChild().getNodeName().equals("#text")) /*&& (childNode.getFirstChild().getNodeValue().trim().length() != 0)*/) {
325                                 xmlDocument.append(childNode.getNodeName(), childNode.getFirstChild().getNodeValue());
326                         } else {
327                                 if (!childNode.getNodeName().equals("#text") || (childNode.getChildNodes().getLength() != 0)) {
328                                         SimpleXML newXML = xmlDocument.append(childNode.getNodeName());
329                                         addDocumentChildren(newXML, childNode);
330                                 }
331                         }
332                 }
333                 return xmlDocument;
334         }
335
336 }