I need to convert an XML to Text using XSLT. The output I got has all the data in a block without the delimiter or new line feed, I feel the position part in the XSLT isn't even getting executed.
Question : I want to test the position of the last child of every parent and include a new line if its the last child (columnvalue) of the parent(currentRow) or a delimiter if it's not.
I have an XML which looks like below:
XML File:
<?xml version='1.0'?>
<webRowSet xmlns='http://java.sun.com/xml/ns/jdbc'>
<data>
<currentRow>
<columnValue><![CDATA[]]></columnValue>
<columnValue><![CDATA[26068384]]></columnValue>
<columnValue><![CDATA[070-0010055-4842MAR18]]></columnValue>
<columnValue>2018-04-25</columnValue>
<columnValue>170.310</columnValue>
<columnValue><![CDATA[UI-004058]]></columnValue>
</currentRow>
<currentRow><columnValue><![CDATA[]]></columnValue>
<columnValue><![CDATA[26068385]]></columnValue>
<columnValue><![CDATA[070-0010058-5739MAR18]]></columnValue>
<columnValue>2018-04-25</columnValue>
<columnValue>209.900</columnValue>
<columnValue><![CDATA[UI-004057]]></columnValue>
</currentRow>
</data></webRowSet>
XSLT:
<?xml version="1.0"?>
<xsl:stylesheet version ="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" omit-xml-declaration="yes" indent="no"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="Delimiter"><xsl:text>|</xsl:text></xsl:variable>
<xsl:variable name="NewLine"><xsl:text> </xsl:text></xsl:variable>
<xsl:template match="/">
<xsl:text>EXPR5_5|VOUCHER_ID|INVOICE_ID|ENTERED_DT|GROSS_AMT|UnifierRecordNo</xsl:text>
<xsl:text> </xsl:text>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="webRowSet/data">
<xsl:for-each select="currentRow">
<xsl:for-each select="columnValue">
<xsl:value-of select="."/>
<xsl:variable name="Rec_position" select="count(../preceding-sibling::columnValue)+1"/>
<xsl:if test="$Rec_position=6"><xsl:value-of select="$NewLine"/></xsl:if>
<xsl:if test="$Rec_position!=6"><xsl:value-of select="$Delimiter"/></xsl:if>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Output in TEXT should be like:
EXPR5_5|VOUCHER_ID|INVOICE_ID|ENTERED_DT|GROSS_AMT|UnifierRecordNo
|26068384|070-0010055-4842MAR18|2018-04-25|170.310|UI-004058
|26068385|070-0010058-5739MAR18|2018-04-25|209.900|UI-004057
You have two problems in your XSLT.
Firstly, you have not accounted for the fact the elements in your XML are in a default namespace, as defined by xmlns='http://java.sun.com/xml/ns/jdbc
on your root element.
If you are indeed only using XSLT 1.0, you have to associate that namespace with a prefix in your XSLT, like so...
xmlns:j="http://java.sun.com/xml/ns/jdbc"
And then use that prefix before all the elements in your select expressions. For example...
<xsl:template match="j:webRowSet/j:data">
Secondly, in your count
expesssion, the ..
represents the parent node, when you really want to count the preceding siblings of the current node, so you should write this...
<xsl:variable name="Rec_position" select="count(preceding-sibling::j:columnValue)+1"/>
Although the position()
function will do just the same thing here.
<xsl:variable name="Rec_position" select="position()"/>
But do you really want to hard-code the number of columns as 6 though? Try this XSLT instead:
<xsl:stylesheet version ="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:j="http://java.sun.com/xml/ns/jdbc">
<xsl:output method="text" omit-xml-declaration="yes" indent="no"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="Delimiter"><xsl:text>|</xsl:text></xsl:variable>
<xsl:variable name="NewLine"><xsl:text> </xsl:text></xsl:variable>
<xsl:template match="/">
<xsl:text>EXPR5_5|VOUCHER_ID|INVOICE_ID|ENTERED_DT|GROSS_AMT|UnifierRecordNo</xsl:text>
<xsl:value-of select="$NewLine"/>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="j:webRowSet/j:data">
<xsl:for-each select="j:currentRow">
<xsl:for-each select="j:columnValue">
<xsl:if test="position() != 1"><xsl:value-of select="$Delimiter" /></xsl:if>
<xsl:value-of select="."/>
</xsl:for-each>
<xsl:value-of select="$NewLine"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Note, if you could use XSLT 2.0, you could write it like this:
<xsl:stylesheet version ="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xpath-default-namespace="http://java.sun.com/xml/ns/jdbc">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="NewLine"><xsl:text> </xsl:text></xsl:variable>
<xsl:template match="/">
<xsl:text>EXPR5_5|VOUCHER_ID|INVOICE_ID|ENTERED_DT|GROSS_AMT|UnifierRecordNo</xsl:text>
<xsl:value-of select="$NewLine"/>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="webRowSet/data">
<xsl:for-each select="currentRow">
<xsl:value-of select="columnValue" separator="|"/>
<xsl:value-of select="$NewLine"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Note the use of xpath-default-namespace
that makes handling default namespaces easier. Also, the use of separator
on the xsl:value-of
which applies when selecting multiple values. (In XSLT 1.0, xsl:value-of
would only display the first value).
You forgot to take the namespace into account. So add xmlns:j="http://java.sun.com/xml/ns/jdbc"
to the xsl:stylesheet
element of your XSLT file. This way you can access all elements with the correct namespace.
With respect to the namespace change your last template to:
<xsl:template match="j:webRowSet/j:data">
<xsl:for-each select="j:currentRow">
<xsl:for-each select="j:columnValue">
<xsl:value-of select="."/>
<xsl:variable name="Rec_position" select="position()"/>
<xsl:if test="$Rec_position=6"><xsl:value-of select="$NewLine"/></xsl:if>
<xsl:if test="$Rec_position < 6"><xsl:value-of select="$Delimiter"/></xsl:if>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
The output is:
EXPR5_5|VOUCHER_ID|INVOICE_ID|ENTERED_DT|GROSS_AMT|UnifierRecordNo
|26068384|070-0010055-4842MAR18|2018-04-25|170.310|UI-004058
|26068385|070-0010058-5739MAR18|2018-04-25|209.900|UI-004057
This is a very simple solution with a minimum of modification.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.