I rarely use XLST and get confusing results when I try to count child nodes in a parent node.
Edit:
The XML is structured as follows:
<?xml version="1.0"?>
<Response>
<result>
<name>Someone</name>
**<rating>4.5</rating>**
<review>
<text>Some review.</text>
</review>
<review>
<text>Another review.</text>
</review>
</result>
<result>
<name>Another one</name>
**<rating>2</rating>**
<review>
<text>Blah, grieve, blah.</text>
</review>
<review>
<text>Blah, grrrrr, blah.</text>
</review>
<review>
<text>Blah, good grrrrr, blah.</text>
</review>
</result>
...
...
</Response>
The template (simplified) is as follows:
**<body>
<xsl:apply-templates/>
</body>**
<xsl:template match="Response/result">
<div class="item">
<div class="name">
<xsl:value-of select="name"/>
</div>
<xsl:if test="rating">
<span class="review-count">
**(<xsl:value-of select="count(review)"/>)**
</span>
</xsl:if>
</div>
</xsl:template>
I do not get the correct child node count from this approach. In addition to the count(review)
, I tried count(descendant::review)
and several xPath variations. I know I'm missing something simple - but what?
Explanation: Using xsl:key , create a mapping from names to the nodes having that name. Then iterate through all unique names, and output the node count for the name. The main trick here is how to iterate through unique names. See the linked page for an explanation of the count(.
The syntax says the count function tells the XSLT processor to count each time in which an XML tag found at the XPATH expression. It returns a number value that specifies the number of sequence elements contained in a sequence of items that passes by. The empty set of the count is returned to 'zero'.
Definition and Usage. The <xsl:number> element is used to determine the integer position of the current node in the source. It is also used to format a number.
<xsl:if test="rating"> <span class="review-count"> **(<xsl:value-of select="count(review)"/>)** </span> </xsl:if>
This will never generate even a single character, because there is no rating
element in the provided XML document. In case you remove the above conditional instruction, then the result contains the wanted count values.
If you indeed have rating
child for at least some review
elements (but failed to show this to us), then you probably also didn't show other important parts of the XML document -- such as a default namespace.
Update:
The OP has provided a more precise XML document, that contains rating
elements.
I can't repro the problem.
This XSLT transformation:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="Response/result">
<div class="item">
<div class="name">
<xsl:value-of select="name"/>
</div>
<xsl:if test="rating">
<span class="review-count">
**(<xsl:value-of select="count(review)"/>)**
</span>
</xsl:if>
</div>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<Response>
<result>
<name>Someone</name>
<rating>4.5</rating>
<review>
<text>Some review.</text>
</review>
<review>
<text>Another review.</text>
</review>
</result>
<result>
<name>Another one</name>
<rating>2</rating>
<review>
<text>Blah, grieve, blah.</text>
</review>
<review>
<text>Blah, grrrrr, blah.</text>
</review>
<review>
<text>Blah, good grrrrr, blah.</text>
</review>
</result>
...
...
</Response>
produces the wanted, correct result:
<div class="item">
<div class="name">Someone</div>
<span class="review-count">
**(2)**
</span>
</div>
<div class="item">
<div class="name">Another one</div>
<span class="review-count">
**(3)**
</span>
</div>
...
...
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