Reputation: 2044
I am new to XSLT. I have looked through the different solutions in this forum but my problem is a little different. Suppose we have a xml:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Transaction>
<operation>DEBIT</operation>
<autoRegistration>true</autoRegistration>
<allowRecurrence>true</allowRecurrence>
<network>VISA</network>
<source>RANDOM</source>
<origin>
<merchant>ABC</merchant>
<transactionId>1234</transactionId>
<channel>SINGLE</channel>
<country>DE</country>
</origin>
<customer>
<number>338317</number>
<eMail>[email protected]</eMail>
<dateOfBirth>1975-06-15</dateOfBirth>
<contact>
<eMail>[email protected]</eMail>
<phoneNumbers></phoneNumbers>
</contact>
<clientInfo>
<ip>123.111.123.123</ip>
<userAgent>Mozilla/5.0 (Windows NT 6.2; WOW64)</userAgent>
<acceptHeader>*/*</acceptHeader>
</clientInfo>
</customer>
</Transaction>
Suppose I need to transform this to CSV using XSLT. I need my CSV as follows:
operation,allowRecurrence,source,merchant
DEBIT,true,RANDOM,ABC
The real world problem is more complex with more nested xml elements. How should I design my XSLT for such a problem such that it handles multiple levels of nested XML elements and prepares a CSV for me. So far I have managed to put together:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:variable name="delimiter" select="','"/>
<!-- define an array containing the fields we are interested in -->
<xsl:variable name="fieldArray">
<field>operation</field>
<field>allowRecurrence</field>
<field>source</field>
<field>merchant</field>
</xsl:variable>
<xsl:param name="fields" select="document('')/*/xsl:variable[@name='fieldArray']/*"/>
<xsl:template match="/">
<xsl:variable name="currNode" select="."/>
<!-- output the header row -->
<xsl:for-each select="$fields">
<xsl:if test="position() != 1">
<xsl:value-of select="$delimiter"/>
</xsl:if>
<xsl:value-of select="."/>
</xsl:for-each>
<!-- output newline -->
<xsl:text>
</xsl:text>
<xsl:for-each select="$fields" >
<xsl:if test="position() != 1">
<xsl:value-of select="$delimiter"/>
</xsl:if>
<xsl:value-of select="$currNode/*/*[name() = current()]"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
I am stuck at the logic <xsl:value-of select="$currNode/*/*[name() = current()]"/>
... How do I vary the level of XML element nesting in this loop.
Upvotes: 0
Views: 649
Reputation: 116982
XML documents are not "arbitrary"; they follow a pre-defined schema. Your best strategy is to tailor your XSLT to the expected schema. In your example, that would mean something like:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:template match="/Transaction">
<xsl:text>operation,allowRecurrence,source,merchant,eMail </xsl:text>
<xsl:value-of select="operation"/>
<xsl:text>,</xsl:text>
<xsl:value-of select="allowRecurrence"/>
<xsl:text>,</xsl:text>
<xsl:value-of select="source"/>
<xsl:text>,</xsl:text>
<xsl:value-of select="origin/merchant"/>
<xsl:text>,</xsl:text>
<xsl:value-of select="customer/eMail"/>
</xsl:template>
</xsl:stylesheet>
Your idea of traversing the document, looking for a node named 'xyx' would fail when there are multiple nodes with the same name. For example, your XML has two eMail
nodes, and your method would never reach the one at customer/contact/eMail
.
Upvotes: 1