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