package org.tizzit.util.xml; import java.io.File; import java.io.InputStream; import java.io.StringReader; import java.io.StringWriter; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.Vector; import java.util.Map.Entry; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.sax.SAXResult; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import org.apache.log4j.Logger; import org.jaxen.BaseXPath; import org.jaxen.JaxenException; import org.jaxen.dom.DOMXPath; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.Text; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; /** * Helperclass for XML/XPath Functionality. * <p>Copyright: Copyright JuwiMacMillan Group GmbH (c) 2008</p> * @author <a href="mailto:s.kulawik@juwimm.com">Sascha-Matthias Kulawik</a> * @author <a href="mailto:eduard.siebert@juwimm.com">Eduard Siebert</a> * company Juwi MacMillan Group GmbH, Walsrode, Germany * @version $Id$ * @since tizzit-common 02.11.2009 */ public final class DOMHelper { private static Logger log = Logger.getLogger(DOMHelper.class); private static DocumentBuilder docBuilder = null; private static DocumentBuilderFactory dbf = null; private static HashMap<String, BaseXPath> xpathCache = new HashMap<String, BaseXPath>(); /** * Static saving of xpath queries reduces the compile time of the query up to 90%. * A complete XPath Query on a more then 100 line XML document will be up to 10 times faster, 0.1 ms instead * of 1 ms (core2duo) * @param xpath * @param namespaces * @return * @throws JaxenException */ public static BaseXPath getXpath(String xpath, Map<String, String> namespaces) throws JaxenException { if (xpathCache.containsKey(xpath + namespaces.hashCode())) { return xpathCache.get(xpath + namespaces.hashCode()); } else { final BaseXPath expression = new DOMXPath(xpath); Set<Entry<String, String>> nsKeys = namespaces.entrySet(); for (Entry<String, String> entry : nsKeys) { expression.addNamespace(entry.getKey(), entry.getValue()); } if (xpathCache.size() > 20000) { log.info("Size of XPath Cache exceeded size of 20000, starting with new cache."); xpathCache = new HashMap<String, BaseXPath>(); } xpathCache.put(xpath + namespaces.hashCode(), expression); return expression; } } static { try { dbf = DocumentBuilderFactory.newInstance(); dbf.setValidating(false); dbf.setNamespaceAware(true); dbf.setFeature("http://xml.org/sax/features/namespaces", true); docBuilder = dbf.newDocumentBuilder(); } catch (Exception exe) { log.error("Fatal Error occured while getting the DocumentBuilderFactory", exe); } } private DOMHelper() { } public static synchronized Document getNewDocument() { Document doc = null; try { doc = docBuilder.newDocument(); } catch (Exception exe) { log.error("unknown error occured", exe); } return doc; } public static String doc2String(Document doc) { StringWriter stringOut = new StringWriter(); try { Transformer t = TransformerFactory.newInstance().newTransformer(); t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); t.setOutputProperty(OutputKeys.STANDALONE, "no"); t.setOutputProperty(OutputKeys.METHOD, "xml"); t.transform(new DOMSource(doc), new StreamResult(stringOut)); } catch (Exception exe) { log.error("unknown error occured", exe); } return stringOut.toString(); } public static String node2String(Node node) { StringWriter stringOut = new StringWriter(); try { Transformer t = TransformerFactory.newInstance().newTransformer(); t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); t.setOutputProperty(OutputKeys.STANDALONE, "no"); t.setOutputProperty(OutputKeys.METHOD, "xml"); t.transform(new DOMSource(node), new StreamResult(stringOut)); } catch (Exception exe) { log.error("unknown error occured", exe); } return stringOut.toString(); } public static void node2sax(Node node, ContentHandler handler) { try { Transformer t = TransformerFactory.newInstance().newTransformer(); t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); t.setOutputProperty(OutputKeys.STANDALONE, "no"); t.setOutputProperty(OutputKeys.METHOD, "xml"); DOMSource source = new DOMSource(node); SAXResult result = new SAXResult(handler); t.transform(source, result); } catch (Exception exe) { log.error("unknown error occured", exe); } } public static void string2sax(String node, ContentHandler handler, String encoding) { try { Transformer t = TransformerFactory.newInstance().newTransformer(); t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); t.setOutputProperty(OutputKeys.STANDALONE, "no"); t.setOutputProperty(OutputKeys.METHOD, "xml"); if (!"".equals(encoding) && encoding != null) { t.setOutputProperty(OutputKeys.ENCODING, encoding); } StreamSource source = new StreamSource(new StringReader(node)); SAXResult result = new SAXResult(new OmitXmlDeclarationContentHandler(handler)); t.transform(source, result); } catch (Exception exe) { log.error("unknown error occured", exe); } } public static void string2sax(String node, ContentHandler handler) { try { Transformer t = TransformerFactory.newInstance().newTransformer(); t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); t.setOutputProperty(OutputKeys.STANDALONE, "no"); t.setOutputProperty(OutputKeys.METHOD, "xml"); StreamSource source = new StreamSource(new StringReader(node)); SAXResult result = new SAXResult(new OmitXmlDeclarationContentHandler(handler)); t.transform(source, result); } catch (Exception exe) { log.error("unknown error occured", exe); } } public static Node findNode(Node node, String xpathquery, HashMap<String, String> namespaces) throws Exception { Iterator<Node> it = findNodes(node, xpathquery, namespaces); if (it.hasNext()) { return it.next(); } return null; } @SuppressWarnings("unchecked") public static Iterator<Node> findNodes(Node node, String xpathquery, Map<String, String> namespaces) { Iterator<Node> it = null; try { BaseXPath expression = getXpath(xpathquery, namespaces); it = expression.selectNodes(node).iterator(); } catch (Exception exe) { } if (it == null) { it = new Vector().iterator(); } return it; } public static String getNodeValue(Node node, String xpath, HashMap<String, String> namespaces) { String retString = ""; try { Node lNode = findNode(node, xpath, namespaces); retString = lNode.getFirstChild().getNodeValue(); } catch (Exception e) { } return retString; } public static String getNodeValue(Node nde) { String retString = ""; try { retString = nde.getFirstChild().getNodeValue(); } catch (Exception e) { } return retString; } public static Node renameNode(Node nde, String strName) { if (!strName.equals(nde.getNodeName())) { Document xdoc = nde.getOwnerDocument(); Element retnode = xdoc.createElement(strName); NodeList nl = nde.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { retnode.appendChild(nl.item(i).cloneNode(true)); } NamedNodeMap al = nde.getAttributes(); for (int i = 0; i < al.getLength(); i++) { Attr attr = (Attr) al.item(i); retnode.setAttribute(attr.getName(), attr.getValue()); } return retnode; } return nde; } /** * Easily creates a new Node, containing Text and returns the new created Node. * @param doc The Node to append to * @param elementName The Name of the new Node * @param elementText The Text to insert into the Node * @return The created Node */ public static Element createTextNode(Node doc, String elementName, String elementText) { Element elm = doc.getOwnerDocument().createElement(elementName); Text elmTxt = doc.getOwnerDocument().createTextNode(elementText); elm.appendChild(elmTxt); doc.appendChild(elm); return elm; } public static synchronized Document file2Dom(File file) throws Exception { return docBuilder.parse(file); } public static synchronized Document inputstream2Dom(InputStream in) throws Exception { return docBuilder.parse(in); //this will be always validated in xerces. Why? } public static synchronized Document inputSource2Dom(InputSource in) throws Exception { return docBuilder.parse(in); } public static synchronized Document string2Dom(String strXML) throws Exception { InputSource in = new InputSource(new StringReader(strXML)); return docBuilder.parse(in); } /** * This ContentHandler is to remove the xml Header. The OMIT_XML_DECLARATION does not work actually. * @author <a href="mailto:j2ee@juwimm.com">Sascha-Matthias Kulawik</a> * company Juwi MacMillan Group GmbH, Walsrode, Germany * @version $Id$ * @since tizzit-common 02.11.2009 */ public static class OmitXmlDeclarationContentHandler extends DefaultHandler implements ContentHandler { private ContentHandler parent; public OmitXmlDeclarationContentHandler(ContentHandler parent) { this.parent = parent; } @Override public void endDocument() throws SAXException { } @Override public void startDocument() throws SAXException { } @Override public void characters(char[] arg0, int arg1, int arg2) throws SAXException { parent.characters(arg0, arg1, arg2); } @Override public void endElement(String arg0, String arg1, String arg2) throws SAXException { parent.endElement(arg0, arg1, arg2); } @Override public void endPrefixMapping(String arg0) throws SAXException { parent.endPrefixMapping(arg0); } @Override public void ignorableWhitespace(char[] arg0, int arg1, int arg2) throws SAXException { parent.ignorableWhitespace(arg0, arg1, arg2); } @Override public void processingInstruction(String arg0, String arg1) throws SAXException { parent.processingInstruction(arg0, arg1); } @Override public void skippedEntity(String arg0) throws SAXException { parent.skippedEntity(arg0); } @Override public void startElement(String arg0, String arg1, String arg2, Attributes arg3) throws SAXException { parent.startElement(arg0, arg1, arg2, arg3); } @Override public void startPrefixMapping(String arg0, String arg1) throws SAXException { parent.startPrefixMapping(arg0, arg1); } } }