3
votes

I now came to the last step of my XSL stylesheet, which needs me to output a number representing the total number of nodes added. Actually, it doesn't seem to be so straight-forward to me:

First of all, I am not counting the nodes from the original xml document, I am going to count certain nodes from the resulting XML(the initial xml document could be empty).

Secondly, I am not counting all of the nodes.

For example, here is a piece of my XSLT code:

<xsl:template name="Loop2000A">
  <Loop2000A>
<HL>
  <HL01>
    <xsl:value-of select="'1'"/>
  </HL01>
  <HL03>
    <xsl:value-of select="'20'"/>
  </HL03>
</HL>
 <xsl:if test="$recbat//provider_taxonomy_qual !='' ">
<PRV>
 <PRV01>
   <xsl:value-of select="'BI'"/>
 </PRV01>
     <PRV02>
   <xsl:value-of select="$recbat//provider_taxonomy_qual"/>
 </PRV02>
<PRV03>
   <xsl:value-of select="$recbat//provider_taxonomy"/>
</PRV03>
   </PRV>
  </xsl:if>
<xsl:call-template name="Loop2010AA"/>

So for this code, and are called segments, and those $recbat etc. are data sources. So want I really want to count is the number of these segments, and it can across different templates(like "Loop2010AA" template above, which is another template), and these segments may have loops, so they may be created 3 times consecutively, which our counter should increment 3 accordingly, or maybe the "if" statement fails, thus no such segment gets created, then the counter should stay the same.

I am not sure the right way to implement this, since most of the tutorial I've googled are about counting the nodes in the original XML documents. One idea now I have is to use the parameter passing, but I have no idea then how to make this parameter a global one?

Alternatively, I am thinking of a more direct way of doing this. Instead of using a counter variable, is there any way that I can generate the output xml document first, then I count the nodes I want in this xml and then generate the TRUE output with the number in it.

1
With a complete stylesheet one could refactor it with a proper functional scan pattern. Without stylesheet I can only suggest a two phase transformation: output everything into a variable and then count the nodes.user357812
@Alejandro: I actually have all my stylesheet in place, and they are chained together by using ("calling-template"). So using shall I look into scan pattern?Kevin
Good question, +1. See my answer for a complete solution. :)Dimitre Novatchev

1 Answers

3
votes

Here is a general way to process the result of a transformation, including counting its nodes:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ext="http://exslt.org/common"
 >
 <xsl:output method="text"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="/">
  <xsl:variable name="vrtfPass1">
   <top>
    <xsl:apply-templates select="*"/>
    <xsl:apply-templates select="*"/>
   </top>
  </xsl:variable>

  <xsl:variable name="vPass2" select="ext:node-set($vrtfPass1)"/>

  <xsl:value-of select="count($vPass2/*/*/*)"/>
 </xsl:template>
</xsl:stylesheet>

when this transformation is applied on the following XML document:

<nums>
 <num>1</num>
 <num>2</num>
 <num>3</num>
 <num>4</num>
 <num>5</num>
</nums>

the correct result is produced:

10

In XSLT 1.0 (only) the use of the xxx:node-set() extension function is generally required in multi-pass processing. THere is no such requirement in XSLT 2.0, which eliminated the infamous RTF "datatype".