View Javadoc
1   /*
2    * Copyright 2005 Filipe Tavares
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.devyant.decorutils.xml;
17  
18  import com.sun.org.apache.xpath.internal.XPathAPI;
19  import org.w3c.dom.Document;
20  import org.w3c.dom.NamedNodeMap;
21  import org.w3c.dom.Node;
22  import org.w3c.dom.NodeList;
23  import org.xml.sax.InputSource;
24  import org.xml.sax.SAXException;
25  
26  import javax.xml.parsers.DocumentBuilder;
27  import javax.xml.parsers.DocumentBuilderFactory;
28  import javax.xml.parsers.ParserConfigurationException;
29  import javax.xml.transform.TransformerException;
30  import java.io.IOException;
31  import java.util.Collection;
32  import java.util.LinkedList;
33  
34  /***
35   * A simple wrapper for XML documents. Each {@link DynaNode} has a set of
36   * attributes which include text data retrieved from child nodes body.
37   *
38   * @author Filipe Tavares
39   * @version $Revision 1.0$ ($Author: ftavares$)
40   * @since 31/Jan/2005 14:22:19
41   */
42  public class SimpleXmlWrapper {
43      /***
44       * The XML document to wrap.
45       */
46      private Document doc;
47  
48      /***
49       * Creates a new <code>SimpleXmlWrapper</code> instance.
50       * @param file The XML file
51       * @throws ParserConfigurationException Thrown by document factory
52       * @throws IOException Thrown by XML parser
53       * @throws SAXException Thrown by XML parser
54       */
55      public SimpleXmlWrapper(final String file)
56          throws ParserConfigurationException, IOException, SAXException {
57          // read the XML doc
58          DocumentBuilderFactory factory =
59                  DocumentBuilderFactory.newInstance();
60          DocumentBuilder builder =
61                  factory.newDocumentBuilder();
62          InputSource is = new InputSource(file);
63          doc = builder.parse(is);
64      }
65  
66      /***
67       * Returns a <code>Collection</code> of the nodes
68       * selected by the XPath query.
69       * @param xpath XPath query
70       * @return <code>Collection</code> of <code>DynaNode</code>'s
71       * @throws TransformerException Thrown by the XPath API
72       */
73      public final Collection getNodes(final String xpath)
74          throws TransformerException {
75          
76          NodeList nodes = XPathAPI.selectNodeList(doc, xpath);
77          return convert(null, nodes);
78      }
79  
80      /***
81       * Returns a <code>Collection</code> of all the nodes in the document.
82       * @return <code>Collection</code> of <code>DynaNode</code>'s
83       * @throws TransformerException Thrown by the XPath API
84       */
85      public final Collection getNodes() throws TransformerException {
86          /*String xpath = "/"+root+"/"+node;
87  
88          NodeList nodes = XPathAPI.selectNodeList(doc, xpath);*/
89  
90          NodeList nodes = doc.getChildNodes();
91  
92          return convert(null, nodes);
93      }
94  
95      /***
96       * Converts the <code>NodeList</code> instance to a <code>Collection</code>
97       * of <code>DynaNode</code>'s.
98       * @param bean The parent node
99       * @param nodes The child nodes
100      * @return <code>Collection</code> of <code>DynaNode</code>'s
101      */
102     private static Collection convert(final DynaNode bean,
103             final NodeList nodes) {
104         LinkedList list = new LinkedList();
105 
106         for (int i = 0; i < nodes.getLength(); i++) {
107             final Node node = nodes.item(i);
108             if (node.getNodeType() == Node.ELEMENT_NODE) {    // element
109                 DynaNode child = getDynaNode(bean, node);
110                 list.add(child);
111             } else if ((node.getNodeType() == Node.TEXT_NODE) // text node
112                     && (bean != null)                         // isn't document
113                     && (bean.getParent() != null)             // isn't root node
114                     && (!node.getNodeValue().matches("^//s$"))) { // !whitespace
115                 bean.getParent()
116                     .set(bean.getName(), node.getNodeValue().trim());
117             }
118         }
119 
120         if (list.isEmpty()) {
121             return null; // if empty, return null for consistency purposes
122         } else {
123             return list;
124         }
125     }
126 
127     /***
128      * Create a <code>DynaNode</code>.
129      * @param parent The parent node
130      * @param node The node
131      * @return A <code>DynaNode</code> instance
132      */
133     private static DynaNode getDynaNode(final DynaNode parent,
134             final Node node) {
135         DynaNode bean = new DynaNode();
136         bean.setName(node.getNodeName());
137         bean.setParent(parent);
138 
139         if (node.hasAttributes()) {
140             NamedNodeMap nodeList = node.getAttributes();
141 
142             for (int i = 0; i < nodeList.getLength(); i++) {
143                 bean.set(nodeList.item(i).getNodeName(),
144                         nodeList.item(i).getNodeValue());
145             }
146         }
147 
148         if (node.hasChildNodes()) {
149             bean.setChildren(convert(bean, node.getChildNodes()));
150         }
151 
152         return bean;
153     }
154 }