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 }