jSite: First commit : verion 4.0 (written by Bombe)
[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. Construct a new XML tree by calling {@link #SimpleXML(String)} and
34  * append new nodes by calling {@link #append(String)}.
35  * 
36  * @author David Roden <droden@gmail.com>
37  * @version $Id:SimpleXML.java 221 2006-03-06 14:46:49Z bombe $
38  */
39 public class SimpleXML {
40
41         /**
42          * A {@link List} containing all child nodes of this node.
43          */
44         private List<SimpleXML> children = new ArrayList<SimpleXML>();
45
46         /**
47          * The name of this node.
48          */
49         private String name = null;
50
51         /**
52          * The value of this node.
53          */
54         private String value = null;
55
56         /**
57          * Constructs a new XML node without a name.
58          */
59         public SimpleXML() {
60                 super();
61         }
62
63         /**
64          * Constructs a new XML node with the specified name.
65          * 
66          * @param name
67          *            The name of the new node
68          */
69         public SimpleXML(String name) {
70                 this.name = name;
71         }
72
73         /**
74          * Returns the child node of this node with the specified name. If there are several child nodes with the specified name only the first node is
75          * returned.
76          * 
77          * @param nodeName
78          *            The name of the child node
79          * @return The child node, or <code>null</code> if there is no child node with the specified name
80          */
81         public SimpleXML getNode(String nodeName) {
82                 for (int index = 0, count = children.size(); index < count; index++) {
83                         if (children.get(index).name.equals(nodeName)) {
84                                 return children.get(index);
85                         }
86                 }
87                 return null;
88         }
89
90         /**
91          * Returns the child node that is specified by the names. The first element of <code>nodeNames</code> is the name of the child node of this
92          * node, the second element of <code>nodeNames</code> is the name of a child node's child node, and so on. By using this method you can descend
93          * into an XML tree pretty fast.
94          * 
95          * <pre>
96          * SimpleXML deepNode = topNode.getNodes(new String[] { &quot;person&quot;, &quot;address&quot;, &quot;number&quot; });
97          * </pre>
98          * 
99          * @param nodeNames
100          * @return A node that is a deep child of this node, or <code>null</code> if the specified node does not eixst
101          */
102         public SimpleXML getNode(String[] nodeNames) {
103                 SimpleXML node = this;
104                 for (String nodeName: nodeNames) {
105                         node = node.getNode(nodeName);
106                 }
107                 return node;
108         }
109
110         /**
111          * Returns all child nodes of this node.
112          * 
113          * @return All child nodes of this node
114          */
115         public SimpleXML[] getNodes() {
116                 return getNodes(null);
117         }
118
119         /**
120          * Returns all child nodes of this node with the specified name. If there are no child nodes with the specified name an empty array is returned.
121          * 
122          * @param nodeName
123          *            The name of the nodes to retrieve, or <code>null</code> to retrieve all nodes
124          * @return All child nodes with the specified name
125          */
126         public SimpleXML[] getNodes(String nodeName) {
127                 List<SimpleXML> resultList = new ArrayList<SimpleXML>();
128                 for (SimpleXML child: children) {
129                         if ((nodeName == null) || child.name.equals(nodeName)) {
130                                 resultList.add(child);
131                         }
132                 }
133                 return resultList.toArray(new SimpleXML[resultList.size()]);
134         }
135
136         /**
137          * Appends a new XML node with the specified name and returns the new node. With this method you can create deep structures very fast.
138          * 
139          * <pre>
140          * SimpleXML mouseNode = topNode.append(&quot;computer&quot;).append(&quot;bus&quot;).append(&quot;usb&quot;).append(&quot;mouse&quot;);
141          * </pre>
142          * 
143          * @param nodeName
144          *            The name of the node to append as a child to this node
145          * @return The new node
146          */
147         public SimpleXML append(String nodeName) {
148                 return append(new SimpleXML(nodeName));
149         }
150
151         /**
152          * Appends a new XML node with the specified name and value and returns the new node.
153          * 
154          * @param nodeName
155          *            The name of the node to append
156          * @param nodeValue
157          *            The value of the node to append
158          * @return The newly appended node
159          */
160         public SimpleXML append(String nodeName, String nodeValue) {
161                 return append(nodeName).setValue(nodeValue);
162         }
163
164         /**
165          * Appends the node with all its child nodes to this node and returns the child node.
166          * 
167          * @param newChild
168          *            The node to append as a child
169          * @return The child node that was appended
170          */
171         public SimpleXML append(SimpleXML newChild) {
172                 children.add(newChild);
173                 return newChild;
174         }
175
176         public void remove(SimpleXML child) {
177                 children.remove(child);
178         }
179         
180         public void remove(String childName) {
181                 SimpleXML child = getNode(childName);
182                 if (child != null) {
183                         remove(child);
184                 }
185         }
186         
187         public void replace(String childName, String value) {
188                 remove(childName);
189                 append(childName, value);
190         }
191         
192         public void replace(SimpleXML childNode) {
193                 remove(childNode.getName());
194                 append(childNode);
195         }
196         
197         public void removeAll() {
198                 children.clear();
199         }
200
201         /**
202          * Sets the value of this node.
203          * 
204          * @param nodeValue
205          *            The new value of this node
206          * @return This node
207          */
208         public SimpleXML setValue(String nodeValue) {
209                 value = nodeValue;
210                 return this;
211         }
212
213         /**
214          * Returns the name of this node.
215          * 
216          * @return The name of this node
217          */
218         public String getName() {
219                 return name;
220         }
221
222         /**
223          * Returns the value of this node.
224          * 
225          * @return The value of this node
226          */
227         public String getValue() {
228                 return value;
229         }
230
231         /**
232          * Creates a {@link Document} from this node and all its child nodes.
233          * 
234          * @return The {@link Document} created from this node
235          */
236         public Document getDocument() {
237                 DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
238                 try {
239                         DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
240                         Document document = documentBuilder.newDocument();
241                         Element rootElement = document.createElement(name);
242                         document.appendChild(rootElement);
243                         addChildren(rootElement);
244                         return document;
245                 } catch (ParserConfigurationException e) {
246                 }
247                 return null;
248         }
249
250         /**
251          * Appends all children of this node to the specified {@link Element}. If a node has a value that is not <code>null</code> the value is
252          * appended as a text node.
253          * 
254          * @param rootElement
255          *            The element to attach this node's children to
256          */
257         private void addChildren(Element rootElement) {
258                 for (SimpleXML child: children) {
259                         Element childElement = rootElement.getOwnerDocument().createElement(child.name);
260                         rootElement.appendChild(childElement);
261                         if (child.value != null) {
262                                 Text childText = rootElement.getOwnerDocument().createTextNode(child.value);
263                                 childElement.appendChild(childText);
264                         } else {
265                                 child.addChildren(childElement);
266                         }
267                 }
268         }
269
270         /**
271          * Creates a SimpleXML node from the specified {@link Document}. The SimpleXML node of the document's top-level node is returned.
272          * 
273          * @param document
274          *            The {@link Document} to create a SimpleXML node from
275          * @return The SimpleXML node created from the document's top-level node
276          */
277         public static SimpleXML fromDocument(Document document) {
278                 SimpleXML xmlDocument = new SimpleXML(document.getFirstChild().getNodeName());
279                 document.normalizeDocument();
280                 return addDocumentChildren(xmlDocument, document.getFirstChild());
281         }
282
283         /**
284          * Appends the child nodes of the specified {@link Document} to this node. Text nodes are converted into a node's value.
285          * 
286          * @param xmlDocument
287          *            The SimpleXML node to append the child nodes to
288          * @param document
289          *            The document whose child nodes to append
290          * @return The SimpleXML node the child nodes were appended to
291          */
292         private static SimpleXML addDocumentChildren(SimpleXML xmlDocument, Node document) {
293                 NodeList childNodes = document.getChildNodes();
294                 for (int childIndex = 0, childCount = childNodes.getLength(); childIndex < childCount; childIndex++) {
295                         Node childNode = childNodes.item(childIndex);
296                         if ((childNode.getChildNodes().getLength() == 1) && (childNode.getFirstChild().getNodeName().equals("#text")) /*&& (childNode.getFirstChild().getNodeValue().trim().length() != 0)*/) {
297                                 xmlDocument.append(childNode.getNodeName(), childNode.getFirstChild().getNodeValue());
298                         } else {
299                                 if (!childNode.getNodeName().equals("#text") || (childNode.getChildNodes().getLength() != 0)) {
300                                         SimpleXML newXML = xmlDocument.append(childNode.getNodeName());
301                                         addDocumentChildren(newXML, childNode);
302                                 }
303                         }
304                 }
305                 return xmlDocument;
306         }
307
308 }