I am creating csv file using the below xsl. I need to handle a condition check that if the XML does not contain an item element then I need to add a default row otherwise it needs to add the elements from the item.
My XML is large and I am using SAXON streaming. When I use both if and for-each elements it throws errors. I need your help to handle this.
Error occurred: Error occurred while transforming: Template rule is not streamable
XSLT
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0">
<xsl:output method="text" encoding="UTF-8" indent="no" omit-xml-declaration="yes"/>
<xsl:mode streamable="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="dq" select="'"'"/>
<xsl:variable name="qcq" select="'","'"/>
<xsl:variable name="lf" select="' '"/>
<xsl:variable name="email" select="'tst@test.com'"/>
<xsl:variable name="product_id" select="'product1'"/>
<xsl:template match="items">
<xsl:text>product_id,email,key</xsl:text>
<xsl:value-of select="' '"/>
<xsl:choose>
<xsl:when test="not(item)">
<xsl:value-of disable-output-escaping="yes" select="concat($dq,$qcq,$email,$qcq,$dq,$lf)"/>
</xsl:when>
<xsl:when test="item">
<xsl:for-each select="item ! copy-of(.)">
<xsl:variable name="p_key" select="id"/>
<xsl:value-of disable-output-escaping="yes" select="concat($dq,$product_id,$qcq,$email,$qcq,$p_key,$dq,$lf)"/>
</xsl:for-each>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Sample XML
<?xml version="1.0" encoding="UTF-8"?>
<items><item><id><![CDATA[040411c47702b29acb4e4120040ee6b937fbb8]]></id></item></items>
no item in xml
<?xml version="1.0" encoding="UTF-8"?>
<items></items>
If the items
element can be empty you can use e.g.
<xsl:template match="items">
<xsl:text>product_id,email,key</xsl:text>
<xsl:value-of select="' '"/>
<xsl:choose>
<xsl:when test="not(has-children())">
<xsl:value-of select="concat($dq,$qcq,$email,$qcq,$dq,$lf)"/>
</xsl:when>
<xsl:otherwise>
<xsl:for-each select="item ! copy-of(.)">
<xsl:variable name="p_key" select="id"/>
<xsl:value-of select="concat($dq,$product_id,$qcq,$email,$qcq,$p_key,$dq,$lf)"/>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
I have removed the disable-output-escaping as it doesn't make sense for output method text in my view.
Another option would be on-empty
:
<xsl:template match="items">
<xsl:text>product_id,email,key</xsl:text>
<xsl:value-of select="' '"/>
<div>
<xsl:for-each select="item ! copy-of(.)">
<xsl:variable name="p_key" select="id"/>
<xsl:value-of select="concat($dq,$product_id,$qcq,$email,$qcq,$p_key,$dq,$lf)"/>
</xsl:for-each>
<xsl:on-empty>
<xsl:value-of select="concat($dq,$qcq,$email,$qcq,$dq,$lf)"/>
</xsl:on-empty>
</div>
</xsl:template>
With output method text
, the div
element of course doesn't produce output, probably could use an xsl:sequence
instead as well.