ingo@1022: /* ingo@1022: * Copyright (c) 2010 by Intevation GmbH ingo@1022: * ingo@1022: * This program is free software under the LGPL (>=v2.1) ingo@1022: * Read the file LGPL.txt coming with the software for details ingo@1022: * or visit http://www.gnu.org/licenses/ if it does not exist. ingo@1022: */ ingo@1022: tim@2: package de.intevation.gnv.util; tim@2: tim@2: import java.io.IOException; tim@2: import java.io.InputStream; ingo@670: import java.io.OutputStream; tim@11: import java.io.StringBufferInputStream; tim@2: import java.io.StringWriter; tim@2: tim@35: import javax.xml.namespace.NamespaceContext; tim@35: import javax.xml.namespace.QName; tim@2: import javax.xml.parsers.DocumentBuilder; tim@2: import javax.xml.parsers.DocumentBuilderFactory; tim@2: import javax.xml.parsers.ParserConfigurationException; tim@2: import javax.xml.transform.Transformer; tim@2: import javax.xml.transform.TransformerConfigurationException; tim@2: import javax.xml.transform.TransformerException; tim@2: import javax.xml.transform.TransformerFactory; tim@2: import javax.xml.transform.TransformerFactoryConfigurationError; tim@2: import javax.xml.transform.dom.DOMSource; tim@2: import javax.xml.transform.stream.StreamResult; tim@35: import javax.xml.xpath.XPath; tim@35: import javax.xml.xpath.XPathConstants; tim@35: import javax.xml.xpath.XPathExpressionException; tim@35: import javax.xml.xpath.XPathFactory; tim@2: tim@2: import org.apache.log4j.Logger; tim@35: import org.w3c.dom.Attr; tim@35: import org.w3c.dom.Document; tim@35: import org.w3c.dom.Element; tim@35: import org.w3c.dom.Node; tim@35: import org.w3c.dom.NodeList; tim@35: import org.xml.sax.SAXException; tim@2: tim@2: /** tim@962: * This class provides many helper-Methods for handling different kinds of tim@962: * XML-stuff. tim@962: * @author Tim Englich tim@962: * @author Sascha L. Teichmann tim@2: */ tim@36: public class XMLUtils { tim@962: tim@962: /** tim@962: * the logger, used to log exceptions and additonaly information tim@962: */ tim@2: private static Logger logger = Logger.getLogger(XMLUtils.class); tim@2: tim@962: /** tim@962: * Constructor tim@962: */ tim@2: public XMLUtils() { tim@2: } tim@2: tim@962: /** tim@962: * Class which could be used to create XML-Elements tim@962: * @author Sascha L. Teichmann tim@962: * tim@962: */ tim@36: public static class ElementCreator { tim@962: tim@962: /** tim@962: * The document the elements should be placed in. tim@962: */ tim@2: protected Document document; tim@962: tim@962: /** tim@962: * The namespace that should be used. tim@962: */ tim@36: protected String ns; tim@962: tim@962: /** tim@962: * The prefix of the namespace that should be used. tim@962: */ tim@36: protected String prefix; tim@2: tim@962: /** tim@962: * Constructor tim@962: * @param document the document the elements should be placed in tim@962: * @param ns the namespace that should be used tim@962: * @param prefix the prefix of the namespace that should be used tim@962: */ tim@2: public ElementCreator(Document document, String ns, String prefix) { tim@2: this.document = document; tim@36: this.ns = ns; tim@36: this.prefix = prefix; tim@2: } tim@2: tim@962: /** tim@962: * Creates a new element using the given name. tim@962: * @param name the name of the new element. tim@962: * @return the new element tim@962: */ tim@2: public Element create(String name) { tim@2: Element element = document.createElementNS(ns, name); tim@2: element.setPrefix(prefix); tim@2: return element; tim@2: } tim@2: tim@962: /** tim@962: * Adds a new attribute to the given element. tim@962: * @param element the element where the attribute should be placed in. tim@962: * @param name the name of the attribute tim@962: * @param value the value of the attribute tim@962: */ tim@2: public void addAttr(Element element, String name, String value) { tim@2: Attr attr = document.createAttributeNS(ns, name); tim@2: attr.setValue(value); tim@2: attr.setPrefix(prefix); tim@2: element.setAttributeNode(attr); tim@2: } tim@2: } // class ElementCreator tim@2: tim@962: /** tim@962: * Creates a new document. tim@962: * @return the new document tim@962: */ ingo@585: public static Document newDocument() { tim@2: try { tim@36: return DocumentBuilderFactory.newInstance().newDocumentBuilder() tim@36: .newDocument(); tim@36: } catch (ParserConfigurationException pce) { tim@2: logger.error(pce.getLocalizedMessage(), pce); tim@2: } tim@2: return null; tim@2: } tim@2: tim@962: /** tim@962: * Creates a new XPath-expression tim@962: * @return the new XPath-expression tim@962: */ ingo@585: public static XPath newXPath() { tim@2: return newXPath(null); tim@2: } tim@2: tim@962: /** tim@962: * Creates a new XPath-expression tim@962: * @param namespaceContext the namespacecontext that should be used. tim@962: * @return the new XPath-expression tim@962: */ ingo@585: public static XPath newXPath(NamespaceContext namespaceContext) { tim@2: XPathFactory factory = XPathFactory.newInstance(); tim@36: XPath xpath = factory.newXPath(); tim@2: if (namespaceContext != null) { tim@2: xpath.setNamespaceContext(namespaceContext); tim@2: } tim@2: return xpath; tim@2: } tim@2: tim@962: /** tim@962: * Fetch the value of an element or attribute from the given resource tim@962: * using the query. tim@962: * @param root the source where the value should be fetch from tim@962: * @param query the query that should be used to fetch the value tim@962: * @param namespaceContext the namespacecontext that must match to tim@962: * fetch the value. tim@962: * @return the value tim@962: */ ingo@585: public static final String xpathString(Object root, String query, tim@38: NamespaceContext namespaceContext) { tim@36: return (String) xpath(root, query, XPathConstants.STRING, tim@36: namespaceContext); tim@2: } tim@2: tim@962: /** tim@962: * Fetch the object rom the given resource using the query. tim@962: * @param root the source where the value should be fetch from tim@962: * @param query the query that should be used to fetch the object tim@962: * @param returnType the Type that must be used to return the object, tim@962: * @param namespaceContext the namespacecontext that must match to tim@962: * fetch the object. tim@962: * @return the value tim@962: */ tim@36: public static final Object xpath(Object root, String query, tim@38: QName returnType, tim@38: NamespaceContext namespaceContext) { tim@2: if (root == null) { tim@2: return null; tim@2: } tim@2: try { tim@962: XPath xpath = XMLUtils.newXPath(namespaceContext); tim@2: if (xpath != null) { tim@2: return xpath.evaluate(query, root, returnType); tim@2: } tim@36: } catch (XPathExpressionException xpee) { tim@2: logger.error(xpee.getLocalizedMessage(), xpee); tim@35: } tim@2: return null; tim@2: } tim@36: tim@962: /** tim@962: * Fetch the object rom the given resource using the query tim@962: * and the default ArtifactNamespaceContext tim@962: * @param root the source where the value should be fetch from tim@962: * @param query the query that should be used to fetch the object tim@962: * @param returnType the Type that must be used to return the object tim@962: * @return the value tim@962: */ ingo@585: public static Object getXPath(Object root, String query, QName returnType) { ingo@389: return getXPath(root,query,returnType,ArtifactNamespaceContext.INSTANCE); ingo@389: } ingo@389: tim@962: /** tim@962: * Fetch the object rom the given resource using the query tim@962: * and the default ArtifactNamespaceContext tim@962: * @param root the source where the value should be fetch from tim@962: * @param query the query that should be used to fetch the object tim@962: * @param returnType the Type that must be used to return the object. tim@964: * @param context the namespacecontext that must match to tim@962: * fetch the object. tim@962: * @return the value tim@962: */ ingo@585: public static Object getXPath( ingo@389: Object root, String query, QName returnType, NamespaceContext context ingo@389: ) { ingo@389: return xpath(root, query, returnType, context); tim@2: } tim@2: tim@962: /** tim@962: * Fetch a Nodeset value from a XML-Fragment or XML-Document using the tim@962: * given query. tim@962: * @param root the source where the String should be fetched from tim@962: * @param query the query that should be used, tim@962: * @return the Nodeset fetched from the source tim@962: */ ingo@585: public static NodeList getNodeSetXPath(Object root, String query) { tim@36: return (NodeList) getXPath(root, query, XPathConstants.NODESET); tim@2: } tim@2: tim@962: /** tim@962: * Fetch a Node from a XML-Fragment or XML-Document using the tim@962: * given query. tim@962: * @param root the source where the Node should be fetched from tim@962: * @param query the query that should be used, tim@962: * @return the Node fetched from the source tim@962: */ ingo@585: public static Node getNodeXPath(Object root, String query) { tim@36: return (Node) getXPath(root, query, XPathConstants.NODE); tim@2: } tim@2: tim@962: /** tim@962: * Fetch a String value from a XML-Fragment or XML-Document using the tim@962: * given query. tim@962: * @param root the source where the String should be fetched from tim@962: * @param xpath the query that should be used, tim@962: * @return the String fetched from the source tim@962: */ ingo@585: public static String getStringXPath(Object root, String xpath) { tim@2: return getStringXPath(root, xpath, null); tim@2: } tim@2: tim@962: /** tim@962: * Fetch a String value from a XML-Fragment or XML-Document using the tim@962: * given query. tim@962: * @param root the source where the String should be fetched from tim@962: * @param query the query that should be used, tim@962: * @param def the default-value that will be returned id no value was found tim@962: * @return the String fetched from the source tim@962: */ ingo@585: public static String getStringXPath(Object root, String query, String def) { tim@36: String s = (String) getXPath(root, query, XPathConstants.STRING); tim@36: return s == null || s.length() == 0 ? def : s; tim@2: } tim@36: tim@962: /** tim@962: * Reads an XML-document from a given InputStream tim@962: * @param inputStream the InputStream where the document tim@962: * should be read from tim@962: * @return the document that could be read. tim@962: */ ingo@570: public static Document readDocument(InputStream inputStream) { tim@2: Document returnValue = null; tim@2: try { tim@36: DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory tim@36: .newInstance(); ingo@389: docBuilderFactory.setNamespaceAware(true); tim@2: DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); tim@36: returnValue = docBuilder.parse(inputStream); tim@2: } catch (ParserConfigurationException e) { tim@36: logger.error(e, e); tim@2: } catch (SAXException e) { tim@36: logger.error(e, e); tim@2: } catch (IOException e) { tim@36: logger.error(e, e); tim@2: } tim@2: return returnValue; tim@2: } tim@36: tim@962: /** tim@962: * Writes an single XML-Node to a string tim@962: * @param node the XML-Node that should be written tim@962: * @return the encoded XML-Node tim@962: */ ingo@585: public static String writeNode2String(Node node) { tim@2: try { tim@11: DOMSource source = new DOMSource(node); tim@11: return writeDOMSource2String(source); tim@2: } catch (TransformerConfigurationException e) { tim@36: logger.error(e, e); tim@2: } catch (TransformerFactoryConfigurationError e) { tim@36: logger.error(e, e); tim@2: } catch (TransformerException e) { tim@36: logger.error(e, e); tim@2: } tim@2: return null; tim@2: } tim@36: tim@962: /** tim@962: * Reinitialize the doument. tim@962: * This is neccessary because the namespace sometimes is invalid tim@962: * using a document which was created and used in the same step. tim@962: * @param document the document which should be reinitialize tim@962: * @return the document tim@962: */ ingo@585: public static Document reInitDocument(Document document) { ingo@585: StringBufferInputStream inputStream = new StringBufferInputStream( ingo@585: writeDocument2String(document)); ingo@585: return readDocument(inputStream); tim@11: } tim@36: tim@962: /** tim@962: * Writes the given Document into a String. tim@962: * This is very helpful for debugging. tim@962: * @param document the document which should be written to the string. tim@962: * @return the encoded xml-document. tim@962: */ ingo@585: public static String writeDocument2String(Document document) { tim@11: try { tim@11: DOMSource source = new DOMSource(document); tim@11: return writeDOMSource2String(source); tim@11: } catch (TransformerConfigurationException e) { tim@36: logger.error(e, e); tim@11: } catch (TransformerFactoryConfigurationError e) { tim@36: logger.error(e, e); tim@11: } catch (TransformerException e) { tim@36: logger.error(e, e); tim@11: } tim@11: return null; tim@11: } tim@11: tim@11: /** tim@962: * Writes a given DOMSource into a String tim@962: * @param source the source that should be written to string tim@962: * @return the encoded DOMSource tim@11: * @throws TransformerFactoryConfigurationError tim@11: * @throws TransformerConfigurationException tim@11: * @throws TransformerException tim@11: */ ingo@585: private static String writeDOMSource2String(DOMSource source) tim@38: throws TransformerFactoryConfigurationError, tim@38: TransformerConfigurationException, tim@38: TransformerException { tim@36: TransformerFactory transformerFactory = TransformerFactory tim@36: .newInstance(); tim@11: Transformer transformer = transformerFactory.newTransformer(); tim@11: StringWriter sw = new StringWriter(); tim@36: StreamResult result = new StreamResult(sw); tim@11: transformer.transform(source, result); tim@11: return sw.getBuffer().toString(); tim@11: } ingo@670: tim@962: /** tim@962: * Writes a given Document to an OutputStream tim@962: * @param document the document that should be written tim@962: * @param out the stream where the document should be written to, tim@962: * @return true if it was successful, false if not. tim@962: */ tim@962: public static boolean toStream(Document document, OutputStream out) { ingo@670: try { ingo@670: Transformer transformer = ingo@670: TransformerFactory.newInstance().newTransformer(); ingo@670: DOMSource source = new DOMSource(document); ingo@670: StreamResult result = new StreamResult(out); ingo@670: transformer.transform(source, result); ingo@670: return true; ingo@670: } ingo@670: catch (TransformerConfigurationException tce) { ingo@670: logger.error(tce.getLocalizedMessage(), tce); ingo@670: } ingo@670: catch (TransformerFactoryConfigurationError tfce) { ingo@670: logger.error(tfce.getLocalizedMessage(), tfce); ingo@670: } ingo@670: catch (TransformerException te) { ingo@670: logger.error(te.getLocalizedMessage(), te); ingo@670: } ingo@670: return false; sascha@681: } tim@2: } tim@2: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8: