Search code examples
javaxmlxsltxsd

Transforming xml and xsd file into a csv file using java and a xsl file


As the title says I have a xml and a xsd file and want to transform them into a csv file using java and structurize it with a xsl file.

At the moment I can only transform my xml file and structurize it with a xsl file with this code in java:

public static void xmlToCSV() throws Exception{
        File stylesheet = new File("style.xsl");
        File xmlSource = new File("xmlData.xml");

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document document = builder.parse(xmlSource);

        StreamSource stylesource = new StreamSource(stylesheet);
        Transformer transformer = TransformerFactory.newInstance().newTransformer(stylesource);
        Source source = new DOMSource(document);
        Result outputTarget = new StreamResult(new File("output.csv"));
        transformer.transform(source, outputTarget);
    }

sytle.xsl:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xsl:template match="Person">
    <xsl:value-of select="Name"/>
    <xsl:text>,</xsl:text>
    <xsl:value-of select="Gender"/>
    <xsl:text>,</xsl:text>
    <xsl:value-of select="Age"/>
    <xsl:text>&#10;</xsl:text>
  </xsl:template>
</xsl:stylesheet>

xmlData.xml:

<?xml version="1.0" encoding="UTF-8"?>
<Document>
    <Person>
        <Name>Bob</Name>
        <Gender>m</Gender>
        <Age>19</Age>
    </Person>
</Document>

Output:

Bob,m,19

In my xsd you can see some limitations I want to have in my csv file:

 <xs:element maxOccurs="1" minOccurs="1" name="Name">
 <xs:element maxOccurs="1" minOccurs="1" name="Gender">
 <xs:element maxOccurs="1" minOccurs="0" name="Age">

What I want:

name,min,max,value
Bob,1,1,Name
m,1,1,Gender
19,0,1,Age

I am pretty new to xsl and don't know how to use the xsd and where. I saw something about import the xsd in your xsl file but it didn't work out for me. I hope I didn't forget some important information. Thank you for your help.


Solution

  • Try this:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    
      <xsl:output method="text"/>
    
      <!--  strip-space: so we have not unwanted linefeeds-->
      <xsl:strip-space elements="*"/>
      
      <!--  document(the uri to the schema.xsd)-->
      <xsl:variable name="schema" select="document('some.xsd')"/>
      <xsl:key name="schema-key" match="xs:element" use="@name" />
    
      <xsl:template match="/">
        <xsl:text>name,min,max,value</xsl:text>
        <xsl:text>&#10;</xsl:text>
        <xsl:apply-templates select="Document/Person"/>
      </xsl:template>
    
      <xsl:template match="Person/*">
        <xsl:variable name="elementName" select="name()"/>
        <xsl:value-of select="text()"/>
        <xsl:text>,</xsl:text>
        <!--  To use a key on a external document in xslt 1.0 we have to change the context to that document -->
        <xsl:for-each select="$schema">
          <xsl:variable name="schemaElement" select="key('schema-key', $elementName)"/>
          <xsl:value-of select="$schemaElement/@minOccurs"/>
          <xsl:text>,</xsl:text>
          <xsl:value-of select="$schemaElement/@maxOccurs"/>
          <xsl:text>,</xsl:text>
        </xsl:for-each>
        <xsl:value-of select="$elementName"/>
        <xsl:text>&#10;</xsl:text>
      </xsl:template>
    </xsl:stylesheet>
    

    will give you the wanted result:

    name,min,max,value
    Bob,1,1,Name
    m,1,1,Gender
    19,0,1,Age