org.pentaho.platform.util.xml.dom4j.XmlDom4JHelper.java Source code

Java tutorial

Introduction

Here is the source code for org.pentaho.platform.util.xml.dom4j.XmlDom4JHelper.java

Source

/*!
 *
 * This program is free software; you can redistribute it and/or modify it under the
 * terms of the GNU General Public License, version 2 as published by the Free Software
 * Foundation.
 *
 * You should have received a copy of the GNU General Public License along with this
 * program; if not, you can obtain a copy at http://www.gnu.org/licenses/gpl-2.0.html
 * or from the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 *
 * Copyright (c) 2002-2018 Hitachi Vantara. All rights reserved.
 *
 */

package org.pentaho.platform.util.xml.dom4j;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Node;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.pentaho.platform.api.util.XmlParseException;
import org.pentaho.platform.util.messages.Messages;
import org.pentaho.platform.util.xml.XMLParserFactoryProducer;
import org.xml.sax.EntityResolver;

import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.URIResolver;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringWriter;
import java.util.Map;

// TODO sbarkdull, exernalize strings, comment methods

/**
 * A set of static methods to help in with: * the construction of XML DOM Documents (org.dom4j.Document) from
 * files, streams, and Strings * in the creation of XML DOM Documents as the result of an XSLT transform *
 * persisting of XML DOM documents to the file system or a <code>Writer</code>. * the encoding of a String of Xml
 * text
 * 
 * Design notes: This class should never have any dependencies (i.e. imports) on anything on org.pentaho or
 * com.pentaho or their decendant packages. In general, methods in the class should not attempt to handle
 * exceptions, but should let the exceptions propogate to the caller to be handled there. Please do not use
 * european-reuse in this class. One of the primary design goals for this class was to construct it in a way that
 * it could be used without change outside of the Pentaho platform. Related XML-helper type code that is dependant
 * on the platform should be moved "up" to XmlHelper.
 */
public class XmlDom4JHelper {

    private static final Log logger = LogFactory.getLog(XmlDom4JHelper.class);

    /**
     * Create a <code>Document</code> from <code>str</code>.
     * 
     * @param str
     *          String containing the XML that will be used to create the Document
     * @param resolver
     *          EntityResolver an instance of an EntityResolver that will resolve any external URIs. See the docs on
     *          EntityResolver. null is an acceptable value.
     * @return <code>Document</code> initialized with the xml in <code>strXml</code>.
     * @throws XmlParseException
     */
    public static Document getDocFromString(final String strXml, final EntityResolver resolver)
            throws XmlParseException {
        Document document = null;
        try {
            document = XmlDom4JHelper.getDocFromStream(new ByteArrayInputStream(strXml.getBytes()), resolver);
        } catch (DocumentException e) {
            throw new XmlParseException(Messages.getInstance()
                    .getErrorString("XmlDom4JHelper.ERROR_0001_UNABLE_TO_GET_DOCUMENT_FROM_STRING"), e); //$NON-NLS-1$
        } catch (IOException e) {
            throw new XmlParseException(
                    Messages.getInstance().getErrorString("XmlDom4JHelper.ERROR_0002_UNSUPPORTED_ENCODING"), e); //$NON-NLS-1$
        }
        return document;
    }

    /**
     * Create a <code>Document</code> from the contents of a file.
     * 
     * @param path
     *          String containing the path to the file containing XML that will be used to create the Document.
     * @param resolver
     *          EntityResolver an instance of an EntityResolver that will resolve any external URIs. See the docs on
     *          EntityResolver. null is an acceptable value.
     * @return <code>Document</code> initialized with the xml in <code>strXml</code>.
     * @throws DocumentException
     *           if the document isn't valid
     * @throws IOException
     *           if the file doesn't exist
     */
    public static Document getDocFromFile(final File file, final EntityResolver resolver)
            throws DocumentException, IOException {
        SAXReader reader = XMLParserFactoryProducer.getSAXReader(resolver);
        return reader.read(file);
    }

    /**
     * Create a <code>Document</code> from the contents of an input stream, where the input stream contains valid
     * XML.
     * 
     * @param inStream
     * @return
     * @throws DocumentException
     * @throws IOException
     */
    public static Document getDocFromStream(final InputStream inStream, final EntityResolver resolver)
            throws DocumentException, IOException {

        SAXReader reader = XMLParserFactoryProducer.getSAXReader(resolver);
        return reader.read(inStream);
    }

    /**
     * Create a <code>Document</code> from the contents of an input stream, where the input stream contains valid
     * XML.
     * 
     * @param inStream
     * @return
     * @throws DocumentException
     * @throws IOException
     */
    public static Document getDocFromStream(final InputStream inStream) throws DocumentException, IOException {

        return XmlDom4JHelper.getDocFromStream(inStream, null);
    }

    /**
     * Use the transform specified by xslSrc and transform the document specified by docSrc, and return the resulting
     * document.
     * 
     * @param xslSrc
     *          StreamSrc containing the xsl transform
     * @param docSrc
     *          StreamSrc containing the document to be transformed
     * @param params
     *          Map of properties to set on the transform
     * @param resolver
     *          URIResolver instance to resolve URI's in the output document.
     * 
     * @return StringBuffer containing the XML results of the transform
     * @throws TransformerConfigurationException
     *           if the TransformerFactory fails to create a Transformer.
     * @throws TransformerException
     *           if actual transform fails.
     */
    protected static final StringBuffer transformXml(final StreamSource xslSrc, final StreamSource docSrc,
            final Map params, final URIResolver resolver)
            throws TransformerConfigurationException, TransformerException {

        StringBuffer sb = null;
        StringWriter writer = new StringWriter();

        TransformerFactory tf = TransformerFactory.newInstance();
        if (null != resolver) {
            tf.setURIResolver(resolver);
        }
        // TODO need to look into compiling the XSLs...
        Transformer t = tf.newTransformer(xslSrc); // can throw
        // TransformerConfigurationException
        // Start the transformation
        if (params != null) {
            for (Map.Entry<String, String> entry : (Iterable<Map.Entry<String, String>>) params.entrySet()) {
                if (entry.getValue() != null) {
                    t.setParameter(entry.getKey(), entry.getValue());
                }
            }
        }
        t.transform(docSrc, new StreamResult(writer)); // can throw
        // TransformerException
        sb = writer.getBuffer();

        return sb;
    }

    /**
     * Convert a W3C Document to a String.
     * 
     * Note: if you are working with a dom4j Document, you can use it's asXml() method.
     * 
     * @param doc
     *          org.w3c.dom.Document to be converted to a String.
     * @return String representing the XML document.
     * 
     * @throws TransformerConfigurationException
     *           If unable to get an instance of a Transformer
     * @throws TransformerException
     *           If the attempt to transform the document fails.
     */
    public static final StringBuffer docToString(final org.w3c.dom.Document doc)
            throws TransformerConfigurationException, TransformerException {

        StringBuffer sb = null;
        StringWriter writer = new StringWriter();

        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer t = tf.newTransformer(); // can throw
        // TransformerConfigurationException

        Source docSrc = new DOMSource(doc);
        t.transform(docSrc, new StreamResult(writer)); // can throw
        // TransformerException
        sb = writer.getBuffer();

        return sb;
    }

    // TODO sbarkdull, this code is duplicated in LocaleHelper
    /**
     * convert any character in the XML input (<code>rawValue</code>) whose code position is greater than or equal to
     * 0x080 to its Numeric Character Reference. For a description of Numeric Character References see:
     * http://www.w3.org/TR/html4/charset.html#h-5.3.1
     * 
     * @param rawValue
     *          String containing the XML to be encoded.
     * @return String containing the encoded XML
     */
    public static String getXmlEncodedString(final String rawValue) {
        StringBuffer value = new StringBuffer();
        for (int n = 0; n < rawValue.length(); n++) {
            int charValue = rawValue.charAt(n);
            if (charValue >= 0x80) {
                value.append("&#x"); //$NON-NLS-1$
                value.append(Integer.toString(charValue, 0x10));
                value.append(";"); //$NON-NLS-1$
            } else {
                value.append((char) charValue);
            }
        }
        return value.toString();

    }

    /**
     * Write an XML document to a file using the specified character encoding.
     * 
     * @param doc
     *          Document to be written
     * @param outputStream
     *          the output stream
     * @param encoding
     *          String specifying the character encoding. Can be null, in which case the default encoding will be
     *          used. See http://java.sun.com/j2se/1.5.0/docs/api/java/io/OutputStreamWriter.html
     * @throws IOException
     */
    public static void saveDom(final Document doc, final OutputStream outputStream, String encoding)
            throws IOException {
        saveDom(doc, outputStream, encoding, false);
    }

    public static void saveDom(final Document doc, final OutputStream outputStream, String encoding,
            boolean suppressDeclaration) throws IOException {
        saveDom(doc, outputStream, encoding, suppressDeclaration, false);
    }

    public static void saveDom(final Document doc, final OutputStream outputStream, String encoding,
            boolean suppressDeclaration, boolean prettyPrint) throws IOException {
        OutputFormat format = prettyPrint ? OutputFormat.createPrettyPrint() : OutputFormat.createCompactFormat();
        format.setSuppressDeclaration(suppressDeclaration);
        if (encoding != null) {
            format.setEncoding(encoding.toLowerCase());
            if (!suppressDeclaration) {
                doc.setXMLEncoding(encoding.toUpperCase());
            }
        }
        XMLWriter writer = new XMLWriter(outputStream, format);
        writer.write(doc);
        writer.flush();
    }

    /**
     * Convenience method to close an input stream and handle (log and throw away) any exceptions. Helps keep code
     * uncluttered.
     * 
     * @param strm
     *          InputStream to be closed
     */
    protected static void closeInputStream(final InputStream strm) {
        if (null != strm) {
            try {
                strm.close();
            } catch (IOException e) {
                XmlDom4JHelper.logger.warn("Failed to close InputStream.", e); //$NON-NLS-1$
            }
        }
    }

    public static String getNodeText(final String xpath, final Node rootNode) {
        return (XmlDom4JHelper.getNodeText(xpath, rootNode, null));
    }

    public static long getNodeText(final String xpath, final Node rootNode, final long defaultValue) {
        String valueStr = XmlDom4JHelper.getNodeText(xpath, rootNode, Long.toString(defaultValue));
        try {
            return Long.parseLong(valueStr);
        } catch (Exception ignored) {
            //ignore
        }
        return defaultValue;
    }

    public static double getNodeText(final String xpath, final Node rootNode, final double defaultValue) {
        String valueStr = XmlDom4JHelper.getNodeText(xpath, rootNode, null);
        if (valueStr == null) {
            return defaultValue;
        }
        try {
            return Double.parseDouble(valueStr);
        } catch (Exception ignored) {
            //ignore
        }
        return defaultValue;
    }

    public static String getNodeText(final String xpath, final Node rootNode, final String defaultValue) {
        if (rootNode == null) {
            return (defaultValue);
        }
        Node node = rootNode.selectSingleNode(xpath);
        if (node == null) {
            return defaultValue;
        }
        return node.getText();
    }

    public static org.dom4j.Document convertToDom4JDoc(final org.w3c.dom.Document doc)
            throws TransformerConfigurationException, TransformerException, TransformerFactoryConfigurationError,
            DocumentException {
        DOMSource source = new DOMSource(doc);
        StreamResult result = new StreamResult(new StringWriter());
        TransformerFactory.newInstance().newTransformer().transform(source, result);
        String theXML = result.getWriter().toString();
        Document dom4jDoc = null;
        try {
            dom4jDoc = getDocFromString(theXML, null);
        } catch (XmlParseException e) {
            throw new TransformerFactoryConfigurationError(e);
        }
        return dom4jDoc;
    }
}