package com.jware.util.xml;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.StringWriter;
import java.util.Properties;

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.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.xerces.dom.DocumentImpl;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;

/**
 * @author jrmt
 */
public class XSLTransform {

    /**
     * 
     */
    public XSLTransform() {
        super();
    }
    
    /**
     * Show how to transform a DOM tree into another DOM tree.
     * This uses the javax.xml.parsers to parse both an XSL file
     * and the XML file into a DOM, and create an output DOM.
     */

    public Document transformDOM2DOM(String xslFile, Document xmlDoc)
      throws TransformerException, TransformerConfigurationException, FileNotFoundException,
             ParserConfigurationException, SAXException, IOException
    {
      Document doc = null;

      StringBuffer w = new StringBuffer();

      TransformerFactory tFactory = TransformerFactory.newInstance();

      if(tFactory.getFeature(DOMSource.FEATURE) && tFactory.getFeature(DOMResult.FEATURE))
      {
        //Instantiate a DocumentBuilderFactory.
        DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();

        // And setNamespaceAware, which is required when parsing xsl files
        dFactory.setNamespaceAware(true);

        //Use the DocumentBuilderFactory to create a DocumentBuilder.
        DocumentBuilder dBuilder = dFactory.newDocumentBuilder();

        //Use the DocumentBuilder to parse the XSL stylesheet.
        Document xslDoc = dBuilder.parse(xslFile);

        // Use the DOM Document to define a DOMSource object.
        DOMSource xslDomSource = new DOMSource(xslDoc);

        // Set the systemId: note this is actually a URL, not a local filename
        xslDomSource.setSystemId(xslFile);

        // Process the stylesheet DOMSource and generate a Transformer.
        Transformer transformer = tFactory.newTransformer(xslDomSource);

        // Use the DOM Document to define a DOMSource object.
        DOMSource xmlDomSource = new DOMSource(xmlDoc);

        // Set the base URI for the DOMSource so any relative URIs it contains can
        // be resolved.
        // xmlDomSource.setSystemId("birds.xml");

        // Create an empty DOMResult for the Result.
        DOMResult domResult = new DOMResult();

        // Perform the transformation, placing the output in the DOMResult.
        transformer.transform(xmlDomSource, domResult);

        doc = new DocumentImpl();
        Node node = doc.importNode(domResult.getNode().getFirstChild(), true);
        doc.appendChild( node );

      }
      else
      {
        throw new org.xml.sax.SAXNotSupportedException("DOM node processing not supported!");
      }
      return doc;
    }

    /**
     * Show how to transform a DOM tree into xml string.
     * This uses the javax.xml.parsers to parse both an XSL file
     * and the XML file into a XML string or HTML string.
     * format can be a "xml" or "html"
     */

    public String transformDOM2String(String xslFile, Document xmlDoc, String format)
      throws TransformerException, TransformerConfigurationException, FileNotFoundException,
             ParserConfigurationException, SAXException, IOException
    {

      StringWriter stringOut = new StringWriter();        //Writer will be a String

      TransformerFactory tFactory = TransformerFactory.newInstance();

      if(tFactory.getFeature(DOMSource.FEATURE) && tFactory.getFeature(DOMResult.FEATURE))
      {
        //Instantiate a DocumentBuilderFactory.
        DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();

        // And setNamespaceAware, which is required when parsing xsl files
        dFactory.setNamespaceAware(true);

        //Use the DocumentBuilderFactory to create a DocumentBuilder.
        DocumentBuilder dBuilder = dFactory.newDocumentBuilder();

        //Use the DocumentBuilder to parse the XSL stylesheet.
        Document xslDoc = dBuilder.parse(xslFile);

        // Use the DOM Document to define a DOMSource object.
        DOMSource xslDomSource = new DOMSource(xslDoc);

        // Set the systemId: note this is actually a URL, not a local filename
        xslDomSource.setSystemId(xslFile);

        // Process the stylesheet DOMSource and generate a Transformer.
        Transformer transformer = tFactory.newTransformer(xslDomSource);

        // Use the DOM Document to define a DOMSource object.
        DOMSource xmlDomSource = new DOMSource(xmlDoc);

        // Set the base URI for the DOMSource so any relative URIs it contains can
        // be resolved.
        // xmlDomSource.setSystemId("birds.xml");

        // Create an empty DOMResult for the Result.
        DOMResult domResult = new DOMResult();

        // Perform the transformation, placing the output in the DOMResult.
        transformer.transform(xmlDomSource, domResult);


        Document doc = new DocumentImpl();
        Node node = doc.importNode(domResult.getNode().getFirstChild(), true);
        doc.appendChild( node );

        TransformerFactory tfactory = TransformerFactory.newInstance();

        // This creates a transformer that does a simple identity transform,
        // and thus can be used for all intents and purposes as a serializer.
        Transformer serializer = tfactory.newTransformer();

        Properties oprops = new Properties();
        oprops.put("method", "xml");
        oprops.put("indent-amount", "2");
        serializer.setOutputProperties(oprops);
        serializer.transform(new DOMSource(doc),
                           new StreamResult(stringOut));

      }
      else
      {
        throw new org.xml.sax.SAXNotSupportedException("DOM node processing not supported!");
      }
      return stringOut.toString();
    }

    public String serializeDOM( Document doc )
      throws TransformerException, TransformerConfigurationException, FileNotFoundException,
             ParserConfigurationException, SAXException, IOException
    {

        StringWriter stringOut = new StringWriter();        //Writer will be a String

        TransformerFactory tfactory = TransformerFactory.newInstance();

        // This creates a transformer that does a simple identity transform,
        // and thus can be used for all intents and purposes as a serializer.
        Transformer serializer = tfactory.newTransformer();

        serializer.setOutputProperty(OutputKeys.METHOD, "xml");
        serializer.setOutputProperty(OutputKeys.INDENT, "yes");
        serializer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
        serializer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
//        serializer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
        
        serializer.transform(new DOMSource(doc),
                           new StreamResult(stringOut));

        StringBuffer s = new StringBuffer();
        s.append(stringOut.toString());

/*      
        int index = - 1;
        while ( (index=s.toString().indexOf("&amp;")) > 0 )
        {
            s.replace(index, index+"&amp;".length(), "&");
        }

        index = - 1;
        while ( (index=s.toString().indexOf("&gt;")) > 0 )
        {
            s.replace(index, index+"&gt;".length(), ">");
        }

        index = - 1;
        while ( (index=s.toString().indexOf("&lt;")) > 0 )
        {
            s.replace(index, index+"&lt;".length(), "<");
        }
*/
        return ( s.toString() );

    }

    /**
     * Serialize a node to String
     */
    public String SerializeNode(Node node)
      throws TransformerException, TransformerConfigurationException, FileNotFoundException,
             ParserConfigurationException, SAXException, IOException
    {

      StringWriter stringOut = new StringWriter();        //Writer will be a String

      TransformerFactory tfactory = TransformerFactory.newInstance();

      // This creates a transformer that does a simple identity transform,
      // and thus can be used for all intents and purposes as a serializer.
      Transformer serializer = tfactory.newTransformer();

      serializer.setOutputProperty(OutputKeys.METHOD, "xml");
      serializer.setOutputProperty(OutputKeys.INDENT, "yes");
      serializer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
      serializer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
      serializer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
      serializer.transform(new DOMSource(node),
                           new StreamResult(stringOut));

      return stringOut.toString();
      
    }

}
