Search code examples
javaxmlxsltsaxon

How to transform each xml node with Saxon XSLT?


How can I use Saxon xslt transformation library to convert an xml file that contains many nodes to a plain csv string? Means, I want Saxon to concatenate each employee entry as csv, and put them all together.

This is the saxon setup, but I don't know how I could not transform an input xml file with it:

    //false = does not required a feature from a licensed version of Saxon.
    Processor processor = new Processor(false);

    XsltCompiler compiler = processor.newXsltCompiler();
    compiler.compile(new StreamSource("transformation.xslt"));

    Serializer serializer = processor.newSerializer();
    serializer.setOutputProperty(Serializer.Property.OMIT_XML_DECLARATION, "yes");

    //TODO 
    //String result = serializer...serializeNodeToString();

I want to transform the following xml:

<employees stage="test">
   <employee>
      <details>
         <name>Joe</name>
         <age>34</age>
      </details>
      <address>
         <street>test</street>
         <nr>12</nr>
      </address>
   </employee>
   <employee>
      <address>....</address>
      <details>
         <!-- note the changed order of elements! -->
         <age>24</age>
         <name>Sam</name>
      </details>
   </employee>
</employees>

The result string should contain the following (one big string with linebreak separated csv lines):

test,Joe,34,test,12\n
test,Sam,24,...\n

Xslt might be similar to:

<xsl:transform version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text"/>
  <xsl:template match="employee">
    <xsl:value-of select="name"/>
    <xsl:value-of select="age"/>
  </xsl:template>
</xsl:transform>

Solution

  • The XSLT template can be modified as below. The elements can be selected according to the required sequence.

    <xsl:template match="employee">
        <xsl:value-of select="ancestor::employees/@stage, details/name, details/age, address/street, address/nr" separator=", " />
        <xsl:text>&#xA;</xsl:text>
    </xsl:template>
    

    After replacing the ... with some dummy values in the <address> element the following output is generated using the above template.

    test, Joe, 34, test, 12
    test, Sam, 24, test1, 123
    

    For transforming the XML (using XSLT) in Java, I use the following code snippet most of the time. This method returns the transformed XML as a String. The required library is saxon9he.jar. You may have to upgrade the library version for using with XSLT 3.0

    public static String transformXML(String xml, InputStream xslFile) {
        String outputXML = null;
        try {
            System.setProperty("javax.xml.transform.TransformerFactory", "net.sf.saxon.TransformerFactoryImpl");
            TransformerFactory factory = TransformerFactory.newInstance();
            Transformer transformer = factory.newTransformer(new StreamSource(xslFile));
            Source xmlStream = new StreamSource(new StringReader(xml));
            StringWriter writer = new StringWriter();
            Result result = new StreamResult(writer);
            transformer.transform(xmlStream, result);
            outputXML = writer.getBuffer().toString();
            writer.close();
        } catch (TransformerConfigurationException tce) {
            tce.printStackTrace();
        } catch (TransformerException te) {
            te.printStackTrace();
        }
        return outputXML;
    }