Reputation: 55
I have the following XML:
<catalog>
<cd>
<title>Empire Burlesque</title>
<artist>Artist 1</artist>
<country>USA</country>
<artist>Artist 2</artist>
<artist>Artist 3</artist>
<company>Columbia</company>
<price>10.90</price>
<year>1985</year>
</cd>
</catalog>
Now in XSLT I want to loop through the child nodes of <cd>
and check if it is a <title>
or <artist>
or <country>
etc... So far I have done the following XSLT:
<xsl:for-each select="catalog/cd">
<table>
<tr>
<th colspan="2"><xsl:value-of select="title"/></th>
</tr>
<xsl:choose>
<xsl:when test="artist">
<xsl:apply-templates select="artist"/>
</xsl:when>
<xsl:when test="country">
<xsl:apply-templates select="country"/>
</xsl:when>
<xsl:when test="company">
<xsl:apply-templates select="company"/>
</xsl:when>
<xsl:when test="price">
<xsl:apply-templates select="price"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="year"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
But for some reason <artist>
is displaying the first one only the others are not displaying. What I want is to display each node in sequence even if there is <artist>
, <country>
and another <artist>
. Does anyone have any ideas?
Upvotes: 0
Views: 3488
Reputation: 122414
You can do this by simply removing the choose
altogether. An xsl:choose
stops as soon as it hits the first successful when
test, essentially you're saying "if there's an artist
then show that, else if there's a country
then show that, else ...".
<xsl:for-each select="catalog/cd">
<table>
<tr>
<th colspan="2"><xsl:value-of select="title"/></th>
</tr>
<xsl:apply-templates select="artist"/>
<xsl:apply-templates select="country"/>
<xsl:apply-templates select="company"/>
<xsl:apply-templates select="price"/>
<xsl:apply-templates select="year"/>
</table>
</xsl:for-each>
You don't need to check whether or not elements exist before you apply templates; apply-templates
will process all the nodes that its select
expression finds, if the select
finds nothing then apply-templates
will simply do nothing.
If you want to process the elements in document order rather than first the artists, then the countries, etc. then just group them into one apply-templates
:
<xsl:apply-templates select="artist | country | company | price | year" />
or if you don't want to have to name all the elements explicitly then move the title
logic into its own template
<xsl:template match="title">
<tr>
<th colspan="2"><xsl:value-of select="."/></th>
</tr>
</xsl:template>
and then your main template can simply be
<xsl:for-each select="catalog/cd">
<table>
<xsl:apply-templates select="*" />
</table>
</xsl:for-each>
Upvotes: 1