Reputation: 151
I have an XML file that I am using XSL to convert into an html page. I would like to loop through the XML file which contains many parent nodes, and then loop through the child nodes and display the result in an HTML table.
So far I am able to loop through the Parent node and sucessful return them, but when I nest a for-each loop inside there to return the attibutes of the child node, I end up returning the attributes of all child nodes in the document and not the ones specific to the parent node.
Can anyone shed a little light on this.
XML:
<AdminReports xmlns="30/11/2011 09:25:58">
<AdminReport ID="1">
<DataSourceInformation DataSourceID="12" Value="DSI_50"/>
</AdminReport>
<AdminReport ID="2">
<DataSourceInformation DataSourceID="23" Value="DSI_30"/>
</AdminReport>
<AdminReport ID="3">
<DataSourceInformation DataSourceID="34" Value="DSI_20"/>
</AdminReport>
</AdminReports>
XSL:
<table border="1" cellspacing="2" width="800" bgcolor="white">
<xsl:for-each select="/*/*[name()='AdminReport']">
<tr bgcolor="9acd32">
<table><th>Admin Report Num:</th></table>
<table><th><xsl:value-ofselect="@ID"/> </th></table>
</tr>
<tr>
<xsl:for-each select="/*/*/*[name()='DataSourceInformation']">
<table><th>Data Report ID:</th></table>
<table><th><xsl:value-of select="@DataSourceID"/></th></table>
</xsl:for-each>
</tr>
</xsl:for-each>
</table>
Upvotes: 0
Views: 810
Reputation: 661
It is easier to think of XSLT as the declarative template matching engine that it is. Look at the xsl:template and xsl:apply-template elements in this sample. Best wishes!
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns="30/11/2011 09:25:58">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/ns:AdminReports">
<table border="1" cellspacing="2" width="800" bgcolor="white">
<xsl:apply-templates select="ns:AdminReport"/>
</table>
</xsl:template>
<xsl:template match ="ns:AdminReport">
<tr bgcolor="9acd32">
<th>Admin Report Num:</th>
<th>
<xsl:value-of select="@ID"/>
</th>
</tr>
<tr>
<xsl:apply-templates select="ns:DataSourceInformation" />
</tr>
</xsl:template>
<xsl:template match="ns:DataSourceInformation" >
<table>
<th>Data Report ID:</th>
</table>
<table>
<th>
<xsl:value-of select="@DataSourceID"/>
</th>
</table>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1
Reputation: 60414
This can be done more cleanly using templates instead of for-each
:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:x="30/11/2011 09:25:58">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<table border="1" cellspacing="2" width="800" bgcolor="white">
<xsl:apply-templates/>
</table>
</xsl:template>
<xsl:template match="x:AdminReport">
<tr bgcolor="9acd32">
<table><th>Admin Report Num:</th></table>
<table><th><xsl:value-of select="@ID"/></th></table>
</tr>
<tr><xsl:apply-templates/></tr>
</xsl:template>
<xsl:template match="x:DataSourceInformation">
<table><th>Data Report ID:</th></table>
<table><th><xsl:value-of select="@DataSourceID"/></th></table>
</xsl:template>
</xsl:stylesheet>
Notes:
x
so that I could reference elements like x:DataSourceInformation
instead of *[name()='DataSourceInformation']
for-each
is rarely needed in XSLT; templates are almost always the more natural solutionfor-each
, then look at @GSerg's answerUpvotes: 2
Reputation: 78155
You're over-compicating this.
select
is relative to the current context node:
<table border="1" cellspacing="2" width="800" bgcolor="white">
<xsl:for-each select="/*/*[name()='AdminReport']">
<tr bgcolor="9acd32">
<table><th>Admin Report Num:</th></table>
<table><th><xsl:value-of select="@ID"/> </th></table>
</tr>
<tr>
<xsl:for-each select="*[name()='DataSourceInformation']">
<table><th>Data Report ID:</th></table>
<table><th><xsl:value-of select="@DataSourceID"/></th></table>
</xsl:for-each>
</tr>
</xsl:for-each>
</table>
Upvotes: 1
Reputation: 18064
There is no space between value-of & select
<xsl:value-ofselect="@ID"/>
It should be <xsl:value-of select="@ID"/>
Upvotes: 0