Reputation: 1095
the following codes changes xml to csv.
when it is applied to the sample data below,
<Addy>
<Row>
<L>1</L>
<LD>Dwelling</LD>
<Th>Passage</Th>
</Row>
</ADDY>
it produces a csv file in this formatincludng the column names
L,LD,Th
1,Dwelling,Passage
the idea is to do away with the column names and add a comma (,) at the end of the last value such that the expected result is
1,Dwelling,passage,
Upvotes: 1
Views: 308
Reputation: 243569
Just modify the template matching /
so that now it should be:
<xsl:template match="/">
<xsl:apply-templates select="*/*" mode="row"/>
</xsl:template>
And if you really want a trailing comma at the end of each line produced, then replace the first occurence of:
<xsl:if test="position() != last()">,</xsl:if>
with:
<xsl:text> </xsl:text>
When only these minimal modifications are performed, the provided code becomes:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:key name="field" match="/*/*/*" use="name()" />
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:apply-templates select="*/*" mode="row"/>
</xsl:template>
<xsl:template match="*" mode="row">
<xsl:variable name="row" select="*" />
<xsl:for-each select="/*/*/*[generate-id() = generate-id(key('field',name())[1])]">
<xsl:variable name="name" select="name()" />
<xsl:apply-templates select="$row[name()=$name]" mode="data" />
<xsl:text>,</xsl:text>
</xsl:for-each>
<xsl:text> </xsl:text>
</xsl:template>
<xsl:template match="*" mode="data">
<xsl:choose>
<xsl:when test="contains(text(),',')">
<xsl:text>"</xsl:text>
<xsl:call-template name="doublequotes">
<xsl:with-param name="text" select="text()" />
</xsl:call-template>
<xsl:text>"</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="." />
</xsl:otherwise>
</xsl:choose>
<xsl:if test="position() != last()">,</xsl:if>
</xsl:template>
<xsl:template name="doublequotes">
<xsl:param name="text" />
<xsl:choose>
<xsl:when test="contains($text,'"')">
<xsl:value-of select="concat(substring-before($text,'"'),'""')" />
<xsl:call-template name="doublequotes">
<xsl:with-param name="text" select="substring-after($text,'"')" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the following XML document (note the different order of the children in the two Row
elements):
<Addy>
<Row>
<L>1</L>
<LD>Dwelling</LD>
<Th>Passage</Th>
</Row>
<Row>
<Th>Bar</Th>
<LD>Foo</LD>
<L>2</L>
</Row>
</Addy>
the wanted, correct result is produced:
1,Dwelling,Passage,
2,Foo,Bar,
Upvotes: 0
Reputation: 122414
If the elements are in the same order for every Row
then you don't need any of the complex Muenchian Grouping, template modes, etc. Just a very simple stylesheet would suffice:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:strip-space elements="*"/>
<xsl:output method="text"/>
<xsl:template match="Row">
<xsl:apply-templates select="*" />
<xsl:text> </xsl:text>
</xsl:template>
<xsl:template match="Row/*">
<xsl:value-of select="." />
<xsl:text>,</xsl:text>
</xsl:template>
</xsl:stylesheet>
Running this on the following input:
<Addy>
<Row>
<L>1</L>
<LD>Dwelling</LD>
<Th>Passage</Th>
</Row>
<Row>
<L>2</L>
<LD>Foo</LD>
<Th>Bar</Th>
</Row>
</Addy>
produces the output you are after, including the trailing comma after the last column value:
1,Dwelling,Passage,
2,Foo,Bar,
Upvotes: 1
Reputation: 143259
Remove
<xsl:for-each select="*/*/*[generate-id() = generate-id(key('field',name())[1])]">
<xsl:value-of select="name()" />
<xsl:if test="position() != last()">,</xsl:if>
</xsl:for-each>
<xsl:text> </xsl:text>
from the template
for /
and add comma:
<xsl:text>, </xsl:text>
in the template
for *
in row
mode.
Upvotes: 1