reformatting
[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          * SimpleXML deepNode = topNode.getNodes(new String[] { &quot;person&quot;, &quot;address&quot;, &quot;number&quot; });
102          * </pre>
103          *
104          * @param nodeNames
105          * @return A node that is a deep child of this node, or <code>null</code> if
106          *         the specified node does not eixst
107          */
108         public SimpleXML getNode(String[] nodeNames) {
109                 SimpleXML node = this;
110                 for (String nodeName: nodeNames) {
111                         node = node.getNode(nodeName);
112                 }
113                 return node;
114         }
115
116         /**
117          * Returns all child nodes of this node.
118          *
119          * @return All child nodes of this node
120          */
121         public SimpleXML[] getNodes() {
122                 return getNodes(null);
123         }
124
125         /**
126          * Returns all child nodes of this node with the specified name. If there
127          * are no child nodes with the specified name an empty array is returned.
128          *
129          * @param nodeName
130          *            The name of the nodes to retrieve, or <code>null</code> to
131          *            retrieve all nodes
132          * @return All child nodes with the specified name
133          */
134         public SimpleXML[] getNodes(String nodeName) {
135                 List<SimpleXML> resultList = new ArrayList<SimpleXML>();
136                 for (SimpleXML child: children) {
137                         if ((nodeName == null) || child.name.equals(nodeName)) {
138                                 resultList.add(child);
139                         }
140                 }
141                 return resultList.toArray(new SimpleXML[resultList.size()]);
142         }
143
144         /**
145          * Appends a new XML node with the specified name and returns the new node.
146          * With this method you can create deep structures very fast.
147          *
148          * <pre>
149          * SimpleXML mouseNode = topNode.append(&quot;computer&quot;).append(&quot;bus&quot;).append(&quot;usb&quot;).append(&quot;mouse&quot;);
150          * </pre>
151          *
152          * @param nodeName
153          *            The name of the node to append as a child to this node
154          * @return The new node
155          */
156         public SimpleXML append(String nodeName) {
157                 return append(new SimpleXML(nodeName));
158         }
159
160         /**
161          * Appends a new XML node with the specified name and value and returns the
162          * new node.
163          *
164          * @param nodeName
165          *            The name of the node to append
166          * @param nodeValue
167          *            The value of the node to append
168          * @return The newly appended node
169          */
170         public SimpleXML append(String nodeName, String nodeValue) {
171                 return append(nodeName).setValue(nodeValue);
172         }
173
174         /**
175          * Appends the node with all its child nodes to this node and returns the
176          * child node.
177          *
178          * @param newChild
179          *            The node to append as a child
180          * @return The child node that was appended
181          */
182         public SimpleXML append(SimpleXML newChild) {
183                 children.add(newChild);
184                 return newChild;
185         }
186
187         public void remove(SimpleXML child) {
188                 children.remove(child);
189         }
190
191         public void remove(String childName) {
192                 SimpleXML child = getNode(childName);
193                 if (child != null) {
194                         remove(child);
195                 }
196         }
197
198         public void replace(String childName, String value) {
199                 remove(childName);
200                 append(childName, value);
201         }
202
203         public void replace(SimpleXML childNode) {
204                 remove(childNode.getName());
205                 append(childNode);
206         }
207
208         public void removeAll() {
209                 children.clear();
210         }
211
212         /**
213          * Sets the value of this node.
214          *
215          * @param nodeValue
216          *            The new value of this node
217          * @return This node
218          */
219         public SimpleXML setValue(String nodeValue) {
220                 value = nodeValue;
221                 return this;
222         }
223
224         /**
225          * Returns the name of this node.
226          *
227          * @return The name of this node
228          */
229         public String getName() {
230                 return name;
231         }
232
233         /**
234          * Returns the value of this node.
235          *
236          * @return The value of this node
237          */
238         public String getValue() {
239                 return value;
240         }
241
242         /**
243          * Returns the value of this node. If the node does not have a value, the
244          * given default value is returned.
245          *
246          *@param defaultValue
247          *            The default value to return if the node does not have a value
248          * @return The value of this node
249          */
250         public String getValue(String defaultValue) {
251                 return (value == null) ? defaultValue : value;
252         }
253
254         /**
255          * Creates a {@link Document} from this node and all its child nodes.
256          *
257          * @return The {@link Document} created from this node
258          */
259         public Document getDocument() {
260                 DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
261                 try {
262                         DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
263                         Document document = documentBuilder.newDocument();
264                         Element rootElement = document.createElement(name);
265                         document.appendChild(rootElement);
266                         addChildren(rootElement);
267                         return document;
268                 } catch (ParserConfigurationException e) {
269                 }
270                 return null;
271         }
272
273         /**
274          * Appends all children of this node to the specified {@link Element}. If a
275          * node has a value that is not <code>null</code> the value is appended as a
276          * text node.
277          *
278          * @param rootElement
279          *            The element to attach this node's children to
280          */
281         private void addChildren(Element rootElement) {
282                 for (SimpleXML child: children) {
283                         Element childElement = rootElement.getOwnerDocument().createElement(child.name);
284                         rootElement.appendChild(childElement);
285                         if (child.value != null) {
286                                 Text childText = rootElement.getOwnerDocument().createTextNode(child.value);
287                                 childElement.appendChild(childText);
288                         } else {
289                                 child.addChildren(childElement);
290                         }
291                 }
292         }
293
294         /**
295          * Creates a SimpleXML node from the specified {@link Document}. The
296          * SimpleXML node of the document's top-level node is returned.
297          *
298          * @param document
299          *            The {@link Document} to create a SimpleXML node from
300          * @return The SimpleXML node created from the document's top-level node
301          */
302         public static SimpleXML fromDocument(Document document) {
303                 SimpleXML xmlDocument = new SimpleXML(document.getFirstChild().getNodeName());
304                 document.normalizeDocument();
305                 return addDocumentChildren(xmlDocument, document.getFirstChild());
306         }
307
308         /**
309          * Appends the child nodes of the specified {@link Document} to this node.
310          * Text nodes are converted into a node's value.
311          *
312          * @param xmlDocument
313          *            The SimpleXML node to append the child nodes to
314          * @param document
315          *            The document whose child nodes to append
316          * @return The SimpleXML node the child nodes were appended to
317          */
318         private static SimpleXML addDocumentChildren(SimpleXML xmlDocument, Node document) {
319                 NodeList childNodes = document.getChildNodes();
320                 for (int childIndex = 0, childCount = childNodes.getLength(); childIndex < childCount; childIndex++) {
321                         Node childNode = childNodes.item(childIndex);
322                         if ((childNode.getChildNodes().getLength() == 1) && (childNode.getFirstChild().getNodeName().equals("#text")) /*&& (childNode.getFirstChild().getNodeValue().trim().length() != 0)*/) {
323                                 xmlDocument.append(childNode.getNodeName(), childNode.getFirstChild().getNodeValue());
324                         } else {
325                                 if (!childNode.getNodeName().equals("#text") || (childNode.getChildNodes().getLength() != 0)) {
326                                         SimpleXML newXML = xmlDocument.append(childNode.getNodeName());
327                                         addDocumentChildren(newXML, childNode);
328                                 }
329                         }
330                 }
331                 return xmlDocument;
332         }
333
334 }