1
votes

I have written java code to get metadata i.e child nodes from .xsd file and pass this metadata as parameter to .xsl file in order to get value according to its correspond name in .xml file and finally it generate output in .csv format

XML document

<personal>
    <details>
        <name>John</name>
        <age>50</age>
        <country>USA</country>
    </details>
    <details>
        <name>Jams</name>
        <age>40</age>
        <country>UK</country>
    </details>
</personal>

** its xsd**

<xs:element minOccurs="0" maxOccurs="unbounded" name="details">
      <xs:complexType>
        <xs:sequence>
          <xs:element minOccurs="0" name="name" type="xs:string" />
          <xs:element minOccurs="0" name="age" type="xs:string" />
          <xs:element minOccurs="0" name="country" type="xs:string" />
          </xs:sequence>
      </xs:complexType>
    </xs:element>

XSLT stylesheet

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:param name="Elements"/>
    <xsl:template match="/">
        <xsl:for-each select="//details">
            <xsl:value-of select="$Elements"/>
            <xsl:value-of select="'&#xA;'"/>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

Java code

public static void main(String args[]) throws Exception {

    //Read the XML data file and code of stylesheet
    File stylesheet = new File("src/style.xsl");
    File xmlSource = new File("src/data.xml");

    //It enables appln to obtain parser to produces DOM object from XML documents
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    DocumentBuilder builder = factory.newDocumentBuilder();
    Document document = builder.parse(xmlSource);

    Document doc = builder.parse (new File("src/structure.xsd")); 
    NodeList list = doc.getElementsByTagName("xs:element"); 

    String cols="";
    //loop to print data
    for(int i = 0 ; i < list.getLength(); i++){
        Element first = (Element)list.item(i);      
        if(first.hasAttributes() && first.getAttributeNode("type") != null){
            String nm = first.getAttribute("name"); 
            cols=cols+nm+",";
        }
    }
    cols=cols.substring(0, cols.length()-1);
    System.out.println(cols);

    //It process XML data into required format by reading .xsl file.
    StreamSource stylesource = new StreamSource(stylesheet);
    Transformer transformer = TransformerFactory.newInstance().newTransformer(stylesource);

    transformer.setParameter("Elements", cols);

    //Object that implements this interface contains the information needed to act as source input (XML source or transformation instructions).
    Source source = new DOMSource(document);

    //Directory in which file need to be save after transformation from xml to csv
    Result outputTarget = new StreamResult(new File("C:/Users/Desktop/a.csv"));

    //Transforming
    transformer.transform(source, outputTarget);
}

Actual Output

I am getting .csv output as

name,age,country
name,age,country

Expected Output is

John,50,USA
Jams,40,UK
1
So the Elements param will be a comma delimited list? This wont work so easily. What you see is exactly the list $Elements, which is "name,age,country name,age,country" and is what you say that you want in <xsl:value-of select="$Elements"/>. What you want is the contents of the tags that match any of the parts of the string. We may have to do a bit of rework here.... - Stefan Hegny
Why do you need to read out the schema and why do you need to read it out in Java code? If you want to output all child element values of the details elements then using e.g. <xsl:for-each select="//details"><xsl:if test="position() > 1"><xsl:text>&#10;</xsl:text><xsl:for-each select="*"><xsl:if test="position() > 1">, </xsl:if><xsl:value-of select="."/></xsl:for-each></xsl:for-each> should do. - Martin Honnen
It would make a different question, but have you considered passing in the XSD to the transformation instead of picking out a comma separated list from it in Java? XSD's are XML, and obviously XSLT is more suited to processing XML than plain text. - Flynn1179

1 Answers

0
votes

Use this transformation (I have given the global parameter $Elements a default value but this will be overridden every time the transformation is invoked from the Java code):

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text"/>
  <xsl:strip-space elements="*"/>
    <xsl:param name="Elements" select="'name,age,country'"/>

    <xsl:template match="details">
        <xsl:apply-templates select="
        *[contains(concat(',',$Elements,','),
                   concat(',',name(),',')
                   )]"/>
        <xsl:value-of select="'&#xA;'"/>
    </xsl:template>

    <xsl:template match="details/*">
      <xsl:if test="not(position()=1)">,</xsl:if>
      <xsl:value-of select="."/>
    </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the provided XML document:

<personal>
    <details>
        <name>John</name>
        <age>50</age>
        <country>USA</country>
    </details>
    <details>
        <name>Jams</name>
        <age>40</age>
        <country>UK</country>
    </details>
</personal>

the wanted, correct result is produced:

John,50,USA
Jams,40,UK