XSL - loop through sub nodes in XML
I whant to loop through a XML file thats look like this:
<node>
<cd name="td1">
<data value="cd1-0" />
<cd name="td2">
<data value="cd1-1" />
</cd>
<cd name="td3">
<data value="cd1-2" />
</cd>
</cd>
<cd name="td4">
<data value="cd2-0" />
</cd>
</node>
This is the result that i what is this.
<html>
<table border="1">
<tr>
<td>cd1-0</td>
<td></td>
</tr> 开发者_运维问答
<tr>
<td></td>
<td>cd1-1</td>
</tr>
<tr>
<td></td>
<td>cd1-2</td>
</tr>
<tr>
<td>cd2-0</td>
<td></td>
</tr>
</table>
</html>
In this examle I have 2 levels on the node cd
. But the level can be infinite. So i need some sort of recursive loop function.
This will work with any level of imbricated cd
elements.
You have to modify a bit to produce the <html>
(and <head/><body>...</body>
) structure, this can be in the match='node'
template.
It will skip the empty trailing <td/>
which are not needed for rendering.
XSL
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:template match="node">
<xsl:element name="table">
<xsl:apply-templates />
</xsl:element>
</xsl:template>
<xsl:template match="cd">
<xsl:element name="tr">
<xsl:for-each select="ancestor::cd">
<xsl:element name="td"/>
</xsl:for-each>
<xsl:element name="td">
<xsl:value-of select="./data/@value" />
</xsl:element>
</xsl:element>
<xsl:apply-templates />
</xsl:template>
</xsl:stylesheet>
Output
<table>
<tr><td>cd1-0</td></tr> <!-- Here the second <td/> is skipped -->
<tr><td/><td>cd1-1</td></tr>
<tr><td/><td>cd1-2</td></tr>
<tr><td>cd2-0</td></tr> <!-- Here the second <td/> is skipped -->
</table>
One way to do it:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<!-- adapt output method and doctype to your needs -->
<xsl:output
method="html"
doctype-system="http://www.w3.org/TR/html4/strict.dtd"
doctype-public="-//W3C//DTD HTML 4.01//EN"
indent="yes"
/>
<!-- the document root becomes html -->
<xsl:template match="/">
<html>
<xsl:apply-templates select="*" />
</html>
</xsl:template>
<!-- node becomes table -->
<xsl:template match="node">
<table border="1">
<xsl:apply-templates select="*" />
</table>
</xsl:template>
<!-- 1st level cd elements (children of node) go into first td -->
<xsl:template match="node/cd">
<tr>
<td><xsl:value-of select="data/@value" /></td>
<td />
</tr>
</xsl:template>
<!-- 2nd level cd elements (children of cd) go into second td -->
<xsl:template match="cd/cd">
<tr>
<td />
<td><xsl:value-of select="data/@value" /></td>
</tr>
</xsl:template>
</xsl:stylesheet>
The XML that you sent does not look like a well formed XML. Leaving that to you, you can use foreach element in xslt.
eg:
<table>
<xsl:for-each select="node/cd">
<tr>
<td>
<xsl:value-of select="data/@value"/>
</td>
</tr>
</xsl:for-each>
</table>
Check this link for more: http://www.w3schools.com/Xsl/xsl_for_each.asp
Hope you got the idea.
Update: Thanks to subtenante for clearing up the xml. You can use template to solve this
<xsl:template match="node">
<html>
<body>
<table border="1">
<xsl:apply-templates select="cd" />
</table>
</body>
</html>
</xsl:template>
<xsl:template match="cd">
<tr>
<td>
<xsl:value-of select="@name" />
</td>
<td>
<xsl:value-of select="data/@value"/>
</td>
</tr>
<xsl:if test="cd">
<xsl:apply-templates select="cd" />
</xsl:if>
</xsl:template>
This will produce the following table:
<table border="1">
<tbody>
<tr>
<td>td1</td>
<td>cd1-0</td>
</tr>
<tr>
<td>td2</td>
<td>cd1-1</td>
</tr>
<tr>
<td>td3</td>
<td>cd1-2</td>
</tr>
<tr>
<td>td4</td>
<td>cd2-0</td>
</tr>
</tbody></table>
The provided xslt needs to be modified a bit to achieve exactly what you want. If you are fine with this. Great.
Source:1
Ramjee
精彩评论