I am trying to convert xml dumps similar to this one
<?xml version="1.0" encoding="UTF-8"?>
<report>
<report_header>
<c1>desc</c1>
<c2>prname</c2>
<c3>prnum</c3>
<c4>cdate</c4>
<c5>phase</c5>
<c6>stype</c6>
<c7>status</c7>
<c8>parent</c8>
<c9>location</c9>
</report_header>
<report_row>
<c1></c1>
<c2>IT Project Message Validation</c2>
<c3>IT-0000021</c3>
<c4>12/14/2010 09:56 AM</c4>
<c5>Preparation</c5>
<c6>IT Projects</c6>
<c7>Active</c7>
<c8>IT</c8>
<c9>/IT/BIOMED</c9>
</report_row>
<report_row>
<c1></c1>
<c2>David, Michael John Morning QA Test</c2>
<c3>IT-0000020</c3>
<c4>12/14/2010 08:12 AM</c4>
<c5>Preparation</c5>
<c6>IT Projects</c6>
<c7>Active</c7>
<c8>IT</c8>
<c9>/IT/BIOMED</c9>
</report_row>
</report>
with the xslt below, to csv. Unfortunately the contains function does not work.
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="report">
<xsl:apply-templates select="report_header"/>
<xsl:apply-templates select="report_row"/>
</xsl:template>
<xsl:template match="report_header">
<xsl:for-each select="*">
<xsl:value-of select="."/>
<xsl:if test="position() != last()">
<xsl:value-of select="','"/>
</xsl:if>
</xsl:for-each>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="report_row">
<xsl:param name="value" />
<xsl:for-each select="*">
<xsl:value-of select="$value" />
<xsl:if test="(contains($value,','))">
<xsl:text>"</xsl:text><xsl:value-of select="."/><xsl:text>"</xsl:text>
</xsl:if>
<xsl:if test="not(contains($value,','))">
<xsl:value-of select="."/>
</xsl:if>
<xsl:if test="position() != last()">
<xsl:value-of select="','"/>
</xsl:if>
</xsl:for-each>
<xsl:if test="position() != last()">
<xsl:text>
</xsl:text>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
I get the following dump. I expected the qualifiers around the prname column on the second row.
desc,prname,prnum,cdate,phase,stype,status,parent,location
,IT Project Message Validation,IT-0000021,12/14/2010 09:56 AM,Preparation,IT Projects,Active,IT,/IT/BIOMED
,David, Michael John Morning QA Test,IT-0000020,12/14/2010 08:12 AM,Preparation,IT Projects,Active,IT,/IT/BIOMED
I have only used the coldfusion xmltransform function to test it.
The provided code has issues, some of them reported in the answer of Mads Hansen.
The main problem is that the code is unnecessarily complicated.
Below is a simple solution that produces what seems to be wanted:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="report_header/*">
<xsl:value-of select="."/>
<xsl:call-template name="processEnd"/>
</xsl:template>
<xsl:template match="report_row/*[contains(., ',')]">
<xsl:text>"</xsl:text>
<xsl:value-of select="."/>
<xsl:text>"</xsl:text>
<xsl:call-template name="processEnd"/>
</xsl:template>
<xsl:template match="report_row/*[not(contains(., ','))]">
<xsl:value-of select="."/>
<xsl:call-template name="processEnd"/>
</xsl:template>
<xsl:template name="processEnd">
<xsl:choose>
<xsl:when test="position() != last()">,</xsl:when>
<xsl:otherwise><xsl:text> </xsl:text></xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<report>
<report_header>
<c1>desc</c1>
<c2>prname</c2>
<c3>prnum</c3>
<c4>cdate</c4>
<c5>phase</c5>
<c6>stype</c6>
<c7>status</c7>
<c8>parent</c8>
<c9>location</c9>
</report_header>
<report_row>
<c1></c1>
<c2>IT Project Message Validation</c2>
<c3>IT-0000021</c3>
<c4>12/14/2010 09:56 AM</c4>
<c5>Preparation</c5>
<c6>IT Projects</c6>
<c7>Active</c7>
<c8>IT</c8>
<c9>/IT/BIOMED</c9>
</report_row>
<report_row>
<c1></c1>
<c2>David, Michael John Morning QA Test</c2>
<c3>IT-0000020</c3>
<c4>12/14/2010 08:12 AM</c4>
<c5>Preparation</c5>
<c6>IT Projects</c6>
<c7>Active</c7>
<c8>IT</c8>
<c9>/IT/BIOMED</c9>
</report_row>
</report>
the wanted, correct result is produced:
desc,prname,prnum,cdate,phase,stype,status,parent,location ,IT Project Message Validation,IT-0000021,12/14/2010 09:56 AM,Preparation,IT Projects,Active,IT,/IT/BIOMED ,"David, Michael John Morning QA Test",IT-0000020,12/14/2010 08:12 AM,Preparation,IT Projects,Active,IT,/IT/BIOMED
I don't think that contains() is your issue.
The issue is that your report_row template has an <xsl:param name="value"/> that is never assigned a value. You have logic that is driven from that param, which never fires. Because $value is empty, it will never contain() , or any other character.
You could get the desired behavior by adding a select attribute to the xsl:param:
<xsl:template match="report_row">
<xsl:param name="value" select="." />
You could simplify your stylesheet and logic by making more of a "push" style, which can be easier to debug and maintain than "pull" style stylesheets that attempt to implement procedural logic in XSLT.
Something like the following stylesheet achieve the same thing:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:apply-templates select="*/report_header/*"/>
<xsl:apply-templates select="*/report_row/*"/>
</xsl:template>
<!-- For all but the last item, apply templates for the content, then add a comma -->
<xsl:template match="*[following-sibling::*]">
<xsl:apply-templates/>
<xsl:text>,</xsl:text>
</xsl:template>
<!-- If it's the last element in a group, add a newline char -->
<xsl:template match="*[not(following-sibling::*)]">
<xsl:apply-templates />
<!--Line break-->
<xsl:text> </xsl:text>
</xsl:template>
<!-- If any values contains a comma, wrap it in quotes -->
<xsl:template match="text()[contains(.,',')]">
<xsl:text>"</xsl:text>
<xsl:value-of select="."/>
<xsl:text>"</xsl:text>
</xsl:template>
</xsl:stylesheet>
Produces the following output:
desc,prname,prnum,cdate,phase,stype,status,parent,location
,IT Project Message Validation,IT-0000021,12/14/2010 09:56 AM,Preparation,IT Projects,Active,IT,/IT/BIOMED
,"David, Michael John Morning QA Test",IT-0000020,12/14/2010 08:12 AM,Preparation,IT Projects,Active,IT,/IT/BIOMED
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With