package org.tigris.juxy.util; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.xml.sax.SAXException; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.*; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; /** * Contains utility methods simplifying DOM creation and transformation. * * @author Pavel Sher */ public class DOMUtil { /** * Creates new empty document. * * @return new empty document. */ public static Document newDocument() { createDocumentBuilderFactory(); try { return docBuilderFactory.newDocumentBuilder().newDocument(); } catch (ParserConfigurationException ex) { logger.fatal("Failed to create document builder", ex); } return null; } /** * Parses specified document content to DOM. * * @param documentContent content of a document to parse * @return parsed document * @throws SAXException */ public static Document parse(String documentContent) throws SAXException { createDocumentBuilderFactory(); ByteArrayInputStream bas = new ByteArrayInputStream(documentContent.getBytes()); try { return docBuilderFactory.newDocumentBuilder().parse(bas); } catch (IOException ex) { logger.fatal("Unexpected error occured", ex); } catch (ParserConfigurationException ex) { logger.fatal("Failed to create document builder", ex); } return null; } /** * Prints DOM to output stream. Uses XSLT identity transform for conversion of DOM to string. * * @param root root node of the document or document itself * @param os stream to output * @throws TransformerException */ public static void printDOM(Node root, OutputStream os) throws TransformerException { identityTransform(root, new StreamResult(os)); } /** * Logs document with specified title if current logging level is DEBUG. * * @param title title of the document, used to identify document printed in debug * @param root root node of the document or document itself */ public static void logDocument(String title, Node root) { if (logger.isDebugEnabled()) { if (root == null) { logger.error("Attempt to debug null document, title = " + title); return; } ByteArrayOutputStream buf = new ByteArrayOutputStream(100); try { DOMUtil.printDOM(root, buf); logger.debug(title + "\n" + buf.toString()); } catch (TransformerException e) { logger.debug("Failed to debug document", e); } } } /** * Returns inner node text. * * @param node node which text to normalize * @return */ public static String innerText(Node node) { StringBuffer result = new StringBuffer(200); DOMIterator it = new DOMIterator(node); while (it.hasNext()) { Node next = (Node) it.next(); if (next.getNodeType() == Node.TEXT_NODE) result.append(next.getNodeValue()); } return result.toString(); } private static void identityTransform(Node root, Result res) throws TransformerException { createTransformerFactory(); Transformer tr = trFactory.newTransformer(); tr.setOutputProperty(OutputKeys.METHOD, "xml"); tr.setOutputProperty(OutputKeys.INDENT, "yes"); tr.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); tr.transform(new DOMSource(root), res); } private static void createTransformerFactory() { if (trFactory == null) trFactory = TransformerFactory.newInstance(); } private static void createDocumentBuilderFactory() { if (docBuilderFactory != null) return; try { logger.debug("creating document builder factory"); docBuilderFactory = DocumentBuilderFactory.newInstance(); } catch (FactoryConfigurationError er) { logger.fatal("Failed to create document builder factory"); throw er; } docBuilderFactory.setNamespaceAware(true); docBuilderFactory.setValidating(false); } private static DocumentBuilderFactory docBuilderFactory = null; private static final Log logger = LogFactory.getLog(DOMUtil.class); private static TransformerFactory trFactory = null; }