001    package biweekly.util;
002    
003    import java.io.IOException;
004    import java.io.Reader;
005    import java.io.StringReader;
006    import java.io.StringWriter;
007    import java.io.Writer;
008    import java.util.ArrayList;
009    import java.util.HashMap;
010    import java.util.List;
011    import java.util.Map;
012    
013    import javax.xml.parsers.DocumentBuilder;
014    import javax.xml.parsers.DocumentBuilderFactory;
015    import javax.xml.parsers.ParserConfigurationException;
016    import javax.xml.transform.Transformer;
017    import javax.xml.transform.TransformerConfigurationException;
018    import javax.xml.transform.TransformerException;
019    import javax.xml.transform.TransformerFactory;
020    import javax.xml.transform.TransformerFactoryConfigurationError;
021    import javax.xml.transform.dom.DOMSource;
022    import javax.xml.transform.stream.StreamResult;
023    
024    import org.w3c.dom.Document;
025    import org.w3c.dom.Element;
026    import org.w3c.dom.Node;
027    import org.w3c.dom.NodeList;
028    import org.xml.sax.InputSource;
029    import org.xml.sax.SAXException;
030    
031    /*
032     Copyright (c) 2013, Michael Angstadt
033     All rights reserved.
034    
035     Redistribution and use in source and binary forms, with or without
036     modification, are permitted provided that the following conditions are met: 
037    
038     1. Redistributions of source code must retain the above copyright notice, this
039     list of conditions and the following disclaimer. 
040     2. Redistributions in binary form must reproduce the above copyright notice,
041     this list of conditions and the following disclaimer in the documentation
042     and/or other materials provided with the distribution. 
043    
044     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
045     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
046     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
047     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
048     ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
049     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
050     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
051     ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
052     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
053     SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
054    
055     The views and conclusions contained in the software and documentation are those
056     of the authors and should not be interpreted as representing official policies, 
057     either expressed or implied, of the FreeBSD Project.
058     */
059    
060    /**
061     * Generic XML utility methods.
062     * @author Michael Angstadt
063     */
064    public class XmlUtils {
065            /**
066             * Creates a new XML document.
067             * @return the XML document
068             */
069            public static Document createDocument() {
070                    try {
071                            DocumentBuilderFactory fact = DocumentBuilderFactory.newInstance();
072                            fact.setNamespaceAware(true);
073                            DocumentBuilder db = fact.newDocumentBuilder();
074                            return db.newDocument();
075                    } catch (ParserConfigurationException e) {
076                            //no complex configurations
077                    }
078                    return null;
079            }
080    
081            /**
082             * Parses an XML string into a DOM.
083             * @param xml the XML string
084             * @return the parsed DOM
085             * @throws SAXException if the string is not valid XML
086             */
087            public static Document toDocument(String xml) throws SAXException {
088                    try {
089                            return toDocument(new StringReader(xml));
090                    } catch (IOException e) {
091                            //reading from string
092                    }
093                    return null;
094            }
095    
096            /**
097             * Parses an XML document from a reader.
098             * @param reader the reader
099             * @return the parsed DOM
100             * @throws SAXException if the XML is not valid
101             * @throws IOException if there is a problem reading from the reader
102             */
103            public static Document toDocument(Reader reader) throws SAXException, IOException {
104                    try {
105                            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
106                            dbf.setNamespaceAware(true);
107                            dbf.setIgnoringComments(true);
108                            DocumentBuilder db = dbf.newDocumentBuilder();
109                            return db.parse(new InputSource(reader));
110                    } catch (ParserConfigurationException e) {
111                            //never thrown because we're not doing anything fancy with the configuration
112                    }
113                    return null;
114            }
115    
116            /**
117             * Converts an XML node to a string.
118             * @param node the XML node
119             * @return the string
120             */
121            public static String toString(Node node) {
122                    return toString(node, new HashMap<String, String>());
123            }
124    
125            /**
126             * Converts an XML node to a string.
127             * @param node the XML node
128             * @param outputProperties the output properties
129             * @return the string
130             */
131            public static String toString(Node node, Map<String, String> outputProperties) {
132                    try {
133                            StringWriter writer = new StringWriter();
134                            toWriter(node, writer, outputProperties);
135                            return writer.toString();
136                    } catch (TransformerException e) {
137                            //writing to string
138                    }
139                    return null;
140            }
141    
142            /**
143             * Writes an XML node to a writer.
144             * @param node the XML node
145             * @param writer the writer
146             * @throws TransformerException if there's a problem writing to the writer
147             */
148            public static void toWriter(Node node, Writer writer) throws TransformerException {
149                    toWriter(node, writer, new HashMap<String, String>());
150            }
151    
152            /**
153             * Writes an XML node to a writer.
154             * @param node the XML node
155             * @param writer the writer
156             * @param outputProperties the output properties
157             * @throws TransformerException if there's a problem writing to the writer
158             */
159            public static void toWriter(Node node, Writer writer, Map<String, String> outputProperties) throws TransformerException {
160                    try {
161                            Transformer transformer = TransformerFactory.newInstance().newTransformer();
162                            for (Map.Entry<String, String> property : outputProperties.entrySet()) {
163                                    try {
164                                            transformer.setOutputProperty(property.getKey(), property.getValue());
165                                    } catch (IllegalArgumentException e) {
166                                            //ignore invalid output properties
167                                    }
168                            }
169    
170                            DOMSource source = new DOMSource(node);
171                            StreamResult result = new StreamResult(writer);
172                            transformer.transform(source, result);
173                    } catch (TransformerConfigurationException e) {
174                            //no complex configurations
175                    } catch (TransformerFactoryConfigurationError e) {
176                            //no complex configurations
177                    }
178            }
179    
180            /**
181             * Gets all the elements out of a {@link NodeList}.
182             * @param nodeList the node list
183             * @return the elements
184             */
185            public static List<Element> toElementList(NodeList nodeList) {
186                    List<Element> elements = new ArrayList<Element>();
187                    for (int i = 0; i < nodeList.getLength(); i++) {
188                            Node node = nodeList.item(i);
189                            if (node instanceof Element) {
190                                    elements.add((Element) node);
191                            }
192                    }
193                    return elements;
194            }
195    
196            /**
197             * Gets the root element of a document.
198             * @param parent the document
199             * @return the root element
200             */
201            public static Element getRootElement(Document parent) {
202                    return getFirstChildElement((Node) parent);
203            }
204    
205            /**
206             * Gets the first child element of an element.
207             * @param parent the parent element
208             * @return the first child element or null if there are no child elements
209             */
210            public static Element getFirstChildElement(Element parent) {
211                    return getFirstChildElement((Node) parent);
212            }
213    
214            /**
215             * Gets the first child element of a node.
216             * @param parent the node
217             * @return the first child element or null if there are no child elements
218             */
219            private static Element getFirstChildElement(Node parent) {
220                    NodeList nodeList = parent.getChildNodes();
221                    for (int i = 0; i < nodeList.getLength(); i++) {
222                            Node node = nodeList.item(i);
223                            if (node instanceof Element) {
224                                    return (Element) node;
225                            }
226                    }
227                    return null;
228            }
229    
230            private XmlUtils() {
231                    //hide
232            }
233    }