1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.apache.jempbox.impl; 18 19 import java.io.File; 20 import java.io.InputStream; 21 import java.io.IOException; 22 import java.io.OutputStream; 23 import java.io.StringWriter; 24 25 import javax.xml.parsers.DocumentBuilder; 26 import javax.xml.parsers.DocumentBuilderFactory; 27 import javax.xml.transform.OutputKeys; 28 import javax.xml.transform.Result; 29 import javax.xml.transform.Transformer; 30 import javax.xml.transform.TransformerException; 31 import javax.xml.transform.TransformerFactory; 32 import javax.xml.transform.dom.DOMSource; 33 import javax.xml.transform.stream.StreamResult; 34 35 import org.apache.jempbox.xmp.Elementable; 36 import org.w3c.dom.Document; 37 import org.w3c.dom.Element; 38 import org.w3c.dom.Node; 39 import org.w3c.dom.NodeList; 40 import org.w3c.dom.Text; 41 import org.xml.sax.InputSource; 42 43 /** 44 * This class with handle some simple XML operations. 45 * 46 * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a> 47 * @author <a href="mailto:chris@oezbek.net">Christopher Oezbek</a> 48 * 49 * @version $Revision: 1.4 $ 50 */ 51 public class XMLUtil 52 { 53 /** 54 * Utility class, should not be instantiated. 55 * 56 */ 57 private XMLUtil() 58 { 59 } 60 61 /** 62 * This will parse an XML stream and create a DOM document. 63 * 64 * @param is The stream to get the XML from. 65 * @return The DOM document. 66 * @throws IOException It there is an error creating the dom. 67 */ 68 public static Document parse( InputStream is ) throws IOException 69 { 70 try 71 { 72 DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); 73 DocumentBuilder builder = builderFactory.newDocumentBuilder(); 74 return builder.parse( is ); 75 } 76 catch( Exception e ) 77 { 78 IOException thrown = new IOException( e.getMessage() ); 79 throw thrown; 80 } 81 } 82 83 /** 84 * This will parse an InputSource and create a DOM document. 85 * 86 * @param is The stream to get the XML from. 87 * @return The DOM document. 88 * @throws IOException It there is an error creating the dom. 89 */ 90 public static Document parse( InputSource is ) throws IOException 91 { 92 try 93 { 94 DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); 95 DocumentBuilder builder = builderFactory.newDocumentBuilder(); 96 return builder.parse( is ); 97 } 98 catch( Exception e ) 99 { 100 IOException thrown = new IOException( e.getMessage() ); 101 throw thrown; 102 } 103 } 104 105 /** 106 * This will parse an XML stream and create a DOM document. 107 * 108 * @param fileName The file to get the XML from. 109 * @return The DOM document. 110 * @throws IOException It there is an error creating the dom. 111 */ 112 public static Document parse( String fileName ) throws IOException 113 { 114 try 115 { 116 DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); 117 DocumentBuilder builder = builderFactory.newDocumentBuilder(); 118 return builder.parse( fileName ); 119 } 120 catch( Exception e ) 121 { 122 IOException thrown = new IOException( e.getMessage() ); 123 throw thrown; 124 } 125 } 126 127 /** 128 * Create a new blank XML document. 129 * 130 * @return The new blank XML document. 131 * 132 * @throws IOException If there is an error creating the XML document. 133 */ 134 public static Document newDocument() throws IOException 135 { 136 try 137 { 138 DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); 139 DocumentBuilder builder = builderFactory.newDocumentBuilder(); 140 return builder.newDocument(); 141 } 142 catch( Exception e ) 143 { 144 IOException thrown = new IOException( e.getMessage() ); 145 throw thrown; 146 } 147 } 148 149 /** 150 * Get the first instance of an element by name. 151 * 152 * @param parent The parent to get the element from. 153 * @param elementName The name of the element to look for. 154 * @return The element or null if it is not found. 155 */ 156 public static Element getElement( Element parent, String elementName ) 157 { 158 Element retval = null; 159 NodeList children = parent.getElementsByTagName( elementName ); 160 if( children.getLength() > 0 ) 161 { 162 retval = (Element)children.item( 0 ); 163 } 164 return retval; 165 } 166 167 /** 168 * Get the integer value of a subnode. 169 * 170 * @param parent The parent element that holds the values. 171 * @param nodeName The name of the node that holds the integer value. 172 * 173 * @return The integer value of the node. 174 */ 175 public static Integer getIntValue( Element parent, String nodeName ) 176 { 177 String intVal = XMLUtil.getStringValue( XMLUtil.getElement( parent, nodeName ) ); 178 Integer retval = null; 179 if( intVal != null ) 180 { 181 retval = new Integer( intVal ); 182 } 183 return retval; 184 } 185 186 /** 187 * Set the integer value of an element. 188 * 189 * @param parent The parent element that will hold this subelement. 190 * @param nodeName The name of the subelement. 191 * @param intValue The value to set. 192 */ 193 public static void setIntValue( Element parent, String nodeName, Integer intValue ) 194 { 195 Element currentValue = getElement( parent, nodeName ); 196 if( intValue == null ) 197 { 198 if( currentValue != null ) 199 { 200 parent.removeChild( currentValue ); 201 } 202 else 203 { 204 //it doesn't exist so we don't need to remove it. 205 } 206 } 207 else 208 { 209 if( currentValue == null ) 210 { 211 currentValue = parent.getOwnerDocument().createElement( nodeName ); 212 parent.appendChild( currentValue ); 213 } 214 XMLUtil.setStringValue( currentValue, intValue.toString() ); 215 } 216 } 217 218 /** 219 * Get the value of a subnode. 220 * 221 * @param parent The parent element that holds the values. 222 * @param nodeName The name of the node that holds the value. 223 * 224 * @return The value of the sub node. 225 */ 226 public static String getStringValue( Element parent, String nodeName ) 227 { 228 return XMLUtil.getStringValue( XMLUtil.getElement( parent, nodeName ) ); 229 } 230 231 /** 232 * Set the value of an element. 233 * 234 * @param parent The parent element that will hold this subelement. 235 * @param nodeName The name of the subelement. 236 * @param nodeValue The value to set. 237 */ 238 public static void setStringValue( Element parent, String nodeName, String nodeValue ) 239 { 240 Element currentValue = getElement( parent, nodeName ); 241 if( nodeValue == null ) 242 { 243 if( currentValue != null ) 244 { 245 parent.removeChild( currentValue ); 246 } 247 else 248 { 249 //it doesn't exist so we don't need to remove it. 250 } 251 } 252 else 253 { 254 if( currentValue == null ) 255 { 256 currentValue = parent.getOwnerDocument().createElement( nodeName ); 257 parent.appendChild( currentValue ); 258 } 259 XMLUtil.setStringValue( currentValue, nodeValue ); 260 } 261 } 262 263 /** 264 * This will get the text value of an element. 265 * 266 * @param node The node to get the text value for. 267 * @return The text of the node. 268 */ 269 public static String getStringValue( Element node ) 270 { 271 String retval = ""; 272 NodeList children = node.getChildNodes(); 273 for( int i=0; i<children.getLength(); i++ ) 274 { 275 Node next = children.item( i ); 276 if( next instanceof Text ) 277 { 278 retval = next.getNodeValue(); 279 } 280 } 281 return retval; 282 } 283 284 /** 285 * This will set the text value of an element. 286 * 287 * @param node The node to get the text value for. 288 * @param value The new value to set the node to. 289 */ 290 public static void setStringValue( Element node, String value ) 291 { 292 NodeList children = node.getChildNodes(); 293 for( int i=0; i<children.getLength(); i++ ) 294 { 295 Node next = children.item( i ); 296 if( next instanceof Text ) 297 { 298 node.removeChild( next ); 299 } 300 } 301 node.appendChild( node.getOwnerDocument().createTextNode( value ) ); 302 } 303 304 /** 305 * Set an XML element document. 306 * 307 * @param parent The parent document to set the value in. 308 * @param name The name of the XML element to set. 309 * @param node The node to set or clear. 310 */ 311 public static void setElementableValue( Element parent, String name, Elementable node ) 312 { 313 NodeList nodes = parent.getElementsByTagName( name ); 314 if( node == null ) 315 { 316 for( int i=0; i<nodes.getLength(); i++ ) 317 { 318 parent.removeChild( nodes.item( i ) ); 319 } 320 } 321 else 322 { 323 if( nodes.getLength() == 0 ) 324 { 325 if( parent.hasChildNodes() ) 326 { 327 Node firstChild = parent.getChildNodes().item( 0 ); 328 parent.insertBefore( node.getElement(), firstChild ); 329 } 330 else 331 { 332 parent.appendChild( node.getElement() ); 333 } 334 } 335 else 336 { 337 Node oldNode = nodes.item( 0 ); 338 parent.replaceChild( node.getElement(), oldNode ); 339 } 340 } 341 } 342 343 /** 344 * Save the XML document to a file. 345 * 346 * @param doc The XML document to save. 347 * @param file The file to save the document to. 348 * @param encoding The encoding to save the file as. 349 * 350 * @throws TransformerException If there is an error while saving the XML. 351 */ 352 public static void save( Document doc, String file, String encoding ) 353 throws TransformerException 354 { 355 try 356 { 357 Transformer transformer = TransformerFactory.newInstance().newTransformer(); 358 transformer.setOutputProperty(OutputKeys.INDENT, "yes"); 359 transformer.setOutputProperty(OutputKeys.ENCODING, encoding); 360 transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); 361 // initialize StreamResult with File object to save to file 362 363 Result result = new StreamResult(new File(file)); 364 DOMSource source = new DOMSource(doc); 365 transformer.transform(source, result); 366 } 367 finally 368 { 369 370 } 371 } 372 373 /** 374 * Save the XML document to an output stream. 375 * 376 * @param doc The XML document to save. 377 * @param outStream The stream to save the document to. 378 * @param encoding The encoding to save the file as. 379 * 380 * @throws TransformerException If there is an error while saving the XML. 381 */ 382 public static void save( Node doc, OutputStream outStream, String encoding ) 383 throws TransformerException 384 { 385 try 386 { 387 Transformer transformer = TransformerFactory.newInstance().newTransformer(); 388 transformer.setOutputProperty(OutputKeys.INDENT, "yes"); 389 transformer.setOutputProperty(OutputKeys.ENCODING, encoding); 390 transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); 391 392 // initialize StreamResult with File object to save to file 393 Result result = new StreamResult(outStream); 394 DOMSource source = new DOMSource(doc); 395 transformer.transform(source, result); 396 } 397 finally 398 { 399 400 } 401 } 402 403 /** 404 * Convert the document to an array of bytes. 405 * 406 * @param doc The XML document. 407 * @param encoding The encoding of the output data. 408 * 409 * @return The XML document as an array of bytes. 410 * 411 * @throws TransformerException If there is an error transforming to text. 412 */ 413 public static byte[] asByteArray( Document doc, String encoding) 414 throws TransformerException 415 { 416 Transformer transformer = TransformerFactory.newInstance().newTransformer(); 417 transformer.setOutputProperty(OutputKeys.INDENT, "yes"); 418 transformer.setOutputProperty(OutputKeys.ENCODING, encoding); 419 transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); 420 421 StringWriter writer = new StringWriter(); 422 Result result = new StreamResult(writer); 423 DOMSource source = new DOMSource(doc); 424 transformer.transform(source, result); 425 return writer.getBuffer().toString().getBytes(); 426 } 427 }