Reputation: 678
I'd like to write an XSLT that will transform an XML document to a CSV file. Here's a sample of the XML:
<?xml version="1.0" encoding="utf-8"?>
<catalog>
<cd id="c1">
<singer id="s1">
<name>Kate</name>
<surname>Apple</surname>
</singer>
<title>Great CD</title>
</cd>
<cd id="c2">
<singer id="s2">
<name>Mary</name>
<surname>Orange</surname>
</singer>
<title>Even better CD</title>
</cd>
</catalog>
The resulting CSV file should be as follows:
singer, title
Kate Apple, Great CD
Mary Orange, Even better CD
I've come up with the following XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
singer,title
<xsl:for-each select="catalog/cd/singer">
<xsl:value-of select="concat(name,' ',surname,'
')" />
</xsl:for-each>
<xsl:for-each select="catalog/cd">
<xsl:value-of select="title"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
The resulting output is close to what I'd like to achieve:
singer,title
Kate Apple
Mary Orange
Great CDEven better CD
but the order of elements in incorrect. How do I fix this?
Upvotes: 0
Views: 411
Reputation: 4753
You loop on singer then loop on CD to get title. You need to loop on CD, then get singer and title in that loop.
something like:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
singer,title
<xsl:for-each select="catalog/cd">
<xsl:value-of select="concat(singer[1]/name,' ',singer[1]/surname,',',title,'
')" />
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
if you have a namespace in your xml like :
<?xml version="1.0" encoding="utf-8"?>
<library xmlns="http://example.net/library/1.0">
<cd id="c1">...
then you have to use namespace on XSLT also:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:l="http://example.net/library/1.0">
<xsl:template match="/">
singer,title
<xsl:for-each select="l:library/l:cd">
<xsl:value-of select="concat(l:singer[1]/l:name,' ',l:singer[1]/l:surname,',',l:title,'
')" />
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Upvotes: 0
Reputation: 116982
If each cd
has one singer
, then why don't you do simply:
<xsl:template match="/catalog">
<xsl:text>singer,title
</xsl:text>
<xsl:for-each select="cd">
<xsl:value-of select="concat(singer/name, ' ', singer/surname, ', ', title, '
')" />
</xsl:for-each>
</xsl:template>
Upvotes: 2
Reputation: 29022
One solution close to a usual CSV is:
<?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" indent="no" />
<xsl:template match="/">
singer,title
<xsl:for-each select="catalog/cd">
<xsl:value-of select="concat(singer/name,' ',singer/surname,',')" />
<xsl:value-of select="concat(title,'
')"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
The output is:
singer,title
Kate Apple,Great CD
Mary Orange,Even better CD
Upvotes: 0