Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XSLT counting child nodes

Tags:

xml

xslt

xpath

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?

like image 382
ron tornambe Avatar asked Jan 04 '13 02:01

ron tornambe


People also ask

How do you count nodes in XSLT?

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(.

How to check count in XSLT?

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'.

What is number () in XSLT?

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.


1 Answers

<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>
  ...
  ...
like image 58
Dimitre Novatchev Avatar answered Sep 21 '22 07:09

Dimitre Novatchev