/*
 * #%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 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.stream.StreamResult;

import org.apache.commons.io.IOUtils;

import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

public class XMLUtil {
    
    public enum TagFormat {
        OPENING, CLOSING, BOTH, EMPTY
    };
    
    /**
     * 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));
    }
    
    /**
     * 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 = DocumentBuilderFactory.newInstance().newDocumentBuilder().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) {
        if (doc == null) {
            return "";
        }
        
        try {
            DOMSource domSource = new DOMSource(doc);
            StringWriter writer = new StringWriter();
            StreamResult result = new StreamResult(writer);
            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer transformer = tf.newTransformer();
            transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.transform(domSource, result);
            return writer.toString();
        } catch (Exception e) {
            return e.toString();
        }
    }
    
    /**
     * 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() {
    }
}

@@ -1319,17 +1319,16 @@
 OUtils;%0A
-%0A
 import o
@@ -3209,24 +3209,347 @@
 ment doc) %7B%0A
+        return toString(doc, 4);%0A    %7D%0A    %0A    /**%0A     * Converts an XML document to a formatted XML string.%0A     * %0A     * @param doc The document to format.%0A     * @param indent Number of characters to indent.%0A     * @return Formatted XML document.%0A     */%0A    public static String toString(Document doc, int indent) %7B%0A
         if (
@@ -3853,24 +3853,78 @@
 Instance();%0A
+            tf.setAttribute(%22indent-number%22, indent);%0A
             

Add indent value to XML serialization.