I am trying to create an html table by querying on an xml document. I am using xslt.
Here is the problem. "parent" node contains many "child" nodes. I have to o/p a table that contains @name of parent and count of "child" nodes in sorted order(descending). So I am doing
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="parent[count(child) > 3]">
<html>
<table border="1">
<xsl:for-each select=".">
<xsl:sort select="{count(child)}" data-type="number" order="descending"/>
<tr>
<td><b><xsl:value-of select="@name" /></b></td>
<td><xsl:value-of select="count(child)" /></td>
</tr>
</xsl:for-each>
</table>
</html>
</xsl:template>
<xsl:template match="text()" />
</xsl:stylesheet>
I get the html however the only problem is I am not getting it in sorted order by count of child elements. I suspect I am using count incorrectly xsl:sort? Can you help?
Input xml
<outer>
<parent name="abc" attr1="22664136" attr2="647500">
<child percentage="11">aaa</child>
<child percentage="35">bbb</child>
<child percentage="50">ccc</child>
</parent>
<parent name="ggg" attr1="3249136" attr2="28750"/>
<parent name="ghi" attr1="29183032" attr2="2381740">
<child2>
<name>ppp</name>
<attr1>1507241</attr1>
</child2>
</parent>
<parent name="qwe" attr1="10342899" attr2="1246700"/>
<parent name="lkj" attr1="65647" attr2="440">
<child percentage="100">jjj</child>
</parent>
</outer>
There are numerous mistakes in the provided XSLT code!
The biggest problem is here:
<xsl:for-each select="."> <xsl:sort select="{count(child)}" data-type="number" order="descending"/> <tr> <td><b><xsl:value-of select="@name" /></b></td> <td><xsl:value-of select="count(child)" /></td> </tr> </xsl:for-each>
This will not perform any meaningful sort, because the node-set of the nodes to be sorted contains only one node -- the current node.
The next problem is here:
<xsl:sort select="{count(child)}" data-type="number" order="descending"/>
There shouldn't be any AVT in any select attribute of an XSLT instruction -- you need to remove the curly braces.
The 3rd problem is that the sort is specified too-late -- inside the template mathcing parent. A parent doesn't have any children that themselves have child children.
Solution: Correcting all major problems, discussed above, one may arrive at the following code:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/*">
<html>
<table border="1">
<xsl:for-each select="parent">
<xsl:sort select="count(child)" data-type="number" order="descending"/>
<tr>
<td>
<b>
<xsl:value-of select="@name" />
</b>
</td>
<td>
<xsl:value-of select="count(child)" />
</td>
</tr>
</xsl:for-each>
</table>
</html>
</xsl:template>
<xsl:template match="text()" />
</xsl:stylesheet>
when this transformation is applied on the provided XML document:
<outer>
<parent name="abc" attr1="22664136" attr2="647500">
<child percentage="11">aaa</child>
<child percentage="35">bbb</child>
<child percentage="50">ccc</child>
</parent>
<parent name="ggg" attr1="3249136" attr2="28750"/>
<parent name="ghi" attr1="29183032" attr2="2381740">
<child2>
<name>ppp</name>
<attr1>1507241</attr1>
</child2>
</parent>
<parent name="qwe" attr1="10342899" attr2="1246700"/>
<parent name="lkj" attr1="65647" attr2="440">
<child percentage="100">jjj</child>
</parent>
</outer>
the wanted-sorted result is produced:
<html>
<table border="1">
<tr>
<td><b>abc</b></td>
<td>3</td>
</tr>
<tr>
<td><b>lkj</b></td>
<td>1</td>
</tr>
<tr>
<td><b>ggg</b></td>
<td>0</td>
</tr>
<tr>
<td><b>ghi</b></td>
<td>0</td>
</tr>
<tr>
<td><b>qwe</b></td>
<td>0</td>
</tr>
</table>
</html>
Almost. You don't need the curly braces around your xsl:sort select="..."
Your for-each would then look like:
<xsl:for-each select=".">
<xsl:sort select="count(child)" data-type="number" order="descending"/>
<tr>
<td><b><xsl:value-of select="@name" /></b></td>
<td><xsl:value-of select="count(child)" /></td>
</tr>
</xsl:for-each>
Edit: Just as an added bit of information, you only use curly braces on literal, result elements. From the XSLT2.0 spec on attribute value templates:
The following example creates an img result element from a photograph element in the source; the value of the src and width attributes are computed using XPath expressions enclosed in attribute value templates:
<xsl:variable name="image-dir" select="'/images'"/> <xsl:template match="photograph"> <img src="{$image-dir}/{href}" width="{size/@width}"/> </xsl:template>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With