org.carewebframework.common.XMLUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.carewebframework.common.XMLUtil.java

Source

/*
 * #%L
 * carewebframework
 * %%
 * Copyright (C) 2008 - 2016 Regenstrief Institute, Inc.
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * This Source Code Form is also subject to the terms of the Health-Related
 * Additional Disclaimer of Warranty and Limitation of Liability available at
 *
 *      http://www.carewebframework.org/licensing/disclaimer.
 *
 * #L%
 */
package org.carewebframework.common;

import java.io.FileInputStream;
import java.io.InputStream;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
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.stream.StreamResult;

import org.apache.commons.io.IOUtils;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;

public class XMLUtil {

    public enum TagFormat {
        OPENING, CLOSING, BOTH, EMPTY
    }

    private static final DocumentBuilderFactory nsUnawareFactory = DocumentBuilderFactory.newInstance();

    private static final DocumentBuilderFactory nsAwareFactory = DocumentBuilderFactory.newInstance();

    static {
        initFactory(nsUnawareFactory, false);
        initFactory(nsAwareFactory, true);
    }

    private static void initFactory(DocumentBuilderFactory factory, boolean nsAware) {
        try {
            factory.setNamespaceAware(nsAware);
            factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
        } catch (ParserConfigurationException e) {
        }
    }

    /**
     * Returns a new document builder instance.
     * 
     * @param nsAware If true, builder will be namespace aware.
     * @return New document builder instance.
     * @throws ParserConfigurationException Parser configuration error.
     */
    public static DocumentBuilder newDocumentBuilder(boolean nsAware) throws ParserConfigurationException {
        return (nsAware ? nsAwareFactory : nsUnawareFactory).newDocumentBuilder();
    }

    /**
     * Parses XML from an input source.
     *
     * @param source An input source containing valid XML.
     * @return XML document.
     * @throws Exception Unspecified exception.
     */
    public static Document parseXMLFromSource(InputSource source) throws Exception {
        return newDocumentBuilder(false).parse(source);
    }

    /**
     * Parses XML from a string.
     *
     * @param xml String containing valid XML.
     * @return XML document.
     * @throws Exception Unspecified exception.
     */
    public static Document parseXMLFromString(String xml) throws Exception {
        return parseXMLFromStream(IOUtils.toInputStream(xml, StandardCharsets.UTF_8));
    }

    /**
     * Parses XML from a list of strings.
     *
     * @param xml String iterable containing valid XML.
     * @return XML document.
     * @throws Exception Unspecified exception.
     */
    public static Document parseXMLFromList(Iterable<String> xml) throws Exception {
        return parseXMLFromString(StrUtil.fromList(xml));
    }

    /**
     * Parses XML from a file.
     *
     * @param filePath Full path to a file containing valid XML.
     * @return XML document.
     * @throws Exception Unspecified exception.
     */
    public static Document parseXMLFromLocation(String filePath) throws Exception {
        return parseXMLFromStream(new FileInputStream(filePath));
    }

    /**
     * Parses XML from an input stream.
     *
     * @param stream Input stream containing valid XML.
     * @return XML document.
     * @throws Exception Unspecified exception.
     */
    public static Document parseXMLFromStream(InputStream stream) throws Exception {
        Document document = newDocumentBuilder(false).parse(stream);
        stream.close();
        return document;
    }

    /**
     * Converts an XML document to a formatted XML string.
     *
     * @param doc The document to format.
     * @return Formatted XML document.
     */
    public static String toString(Document doc) {
        return toString(doc, 4);
    }

    /**
     * Converts an XML document to a formatted XML string.
     *
     * @param doc The document to format.
     * @param indent Number of characters to indent.
     * @return Formatted XML document.
     */
    public static String toString(Document doc, int indent) {
        if (doc == null) {
            return "";
        }

        try {
            DOMSource domSource = new DOMSource(doc);
            StringWriter writer = new StringWriter();
            StreamResult result = new StreamResult(writer);
            TransformerFactory tf = TransformerFactory.newInstance();

            try {
                tf.setAttribute("indent-number", indent);
            } catch (IllegalArgumentException e) {
                // Ignore if not supported.
            }

            Transformer transformer = tf.newTransformer();
            transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", Integer.toString(indent));
            transformer.transform(domSource, result);
            return writer.toString();
        } catch (Exception e) {
            throw MiscUtil.toUnchecked(e);
        }
    }

    /**
     * Returns the formatted name for the node.
     *
     * @param node Node to format.
     * @param format Desired format (opening tag, closing tag, empty tag, or both).
     * @return Formatted name.
     */
    public static String formatNodeName(Node node, TagFormat format) {
        StringBuilder sb = new StringBuilder((format == TagFormat.CLOSING ? "</" : "<") + node.getNodeName());

        if (format != TagFormat.CLOSING) {
            sb.append(formatAttributes(node));
        }

        sb.append(format == TagFormat.EMPTY ? " />" : ">");

        if (format == TagFormat.BOTH) {
            sb.append(formatNodeName(node, TagFormat.CLOSING));
        }

        return sb.toString();
    }

    /**
     * Returns formatted attributes of the node.
     *
     * @param node The node.
     * @return Formatted attributes.
     */
    public static String formatAttributes(Node node) {
        StringBuilder sb = new StringBuilder();
        NamedNodeMap attrs = node.getAttributes();

        for (int i = 0; i < attrs.getLength(); i++) {
            Node attr = attrs.item(i);
            sb.append(' ').append(attr.getNodeName()).append("= '").append(attr.getNodeValue()).append("'");
        }

        return sb.toString();
    }

    /**
     * Enforce static class.
     */
    private XMLUtil() {
    }
}