Altova Mailing List Archives


Re: counter

From: Jeni Tennison <Jeni.Tennison@---------------->
To:
Date: 6/21/2000 6:23:00 PM
Nick,

>Kay Michael wrote:
>The way to print something every fifty <item> elements is:
>>
>> <xsl:template match="item[position() mod 50 = 1]">
>> <fifty-items>
>> Here's the next 50:
>> <xsl:for-each select=". | following-sibling::item[position() &lt; 50]">
>>   <item><xsl:value-of select="."/></item>
>> </xsl:for-each>
>> </fifty-items>
>> </xsl:template>
>
>Having tried this solution and some variations I had a couple of questions (I
>presume that this template was called by <xsl:apply-templates select="item">)
>
>a. I found that when running this I was getting the item content repeated in 
>the ouput for each element where the expression in the template match 
>attribute was false. I put this down to a built-in template being called for 
>those elements, is this correct ?

That's right.  The built-in templates include:

<xsl:template match="*|/">
  <xsl:apply-templates/>
</xsl:template>

which steps through the document, processing the root node, the document
element, and its descedents, including its content and:

<xsl:template match="text()|@*">
  <xsl:value-of select="."/>
</xsl:template>

which matches any text that's found (or attribute values) and gives the
value of that text.  When you only want to process some particular
elements, but the elements that you *don't* want to process contain text,
you have to make sure that you are processing only the elements you *do*
want to process.  You can do this in three ways:

1. move the filtering XPath from the 'match' attribute of the xsl:template
to the 'select' attribute of the xsl:apply-template that calls it (as you
have done):

<xsl:template match="root">
  <xsl:apply-templates select="item[position() mod $cntr = 1]"/>
</xsl:template>

<xsl:template match="item">
  <xsl:for-each select=". | following-sibling::item[position() &lt; $cntr]">
    Item <xsl:value-of select="."/>
 </xsl:for-each>
</xsl:template>

2. put the content of the xsl:template within an xsl:if that tests on the
filter that you're using, and change the templates to match all (wanted and
not wanted) elements, so something like:

<xsl:template match="item">
  <xsl:if test="position() mod $cntr = 1">
    <xsl:for-each select=". |
                          following-sibling::item[position() &lt; $cntr]">
      Item <xsl:value-of select="."/>
    </xsl:for-each>
  </xsl:if>
</xsl:template>

3. add a mode to the template and make sure that the xsl:apply-templates
that calls it only calls templates in that mode, so something like:

<xsl:template match="root">
  <xsl:apply-templates mode="grouped" />
</xsl:template>

<xsl:template match="item[position() mod $cntr = 1]" mode="grouped">
  <xsl:for-each select=". | following-sibling::item[position() &lt; $cntr]">
    Item <xsl:value-of select="."/>
  </xsl:for-each>
</xsl:template>

>However I did notice a significant
>performance improvement over Mike's code which was disproportionate to the
>number of item elements in the source document.

Mike will be able to tell you better than I can about this, but I suspect
that it's because in the original code, the items that were not picked up
by your template were first processed by the built-in template for
elements, and then their content processed by the built-in template for
text, before outputting the value of the item.

Searching for templates takes time, so filtering down the nodes that you
have to search for templates that match on benefits you, as does using
<xsl:value-of select="." /> rather than <xsl:apply-templates /> when you
know that the content of an element is just text [1].

Based on that, Options 1 and 3, which both filter within the
xsl:apply-templates are probably better than Option 2 in most cases.

Cheers,

Jeni

[1] #8 of Mike's Eight tips for how to write efficient XSLT at
http://www.mulberrytech.com/xsl/xsl-list/archive/msg13316.html


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list

Disclaimer

These Archives are provided for informational purposes only and have been generated directly from the Altova mailing list archive system and are comprised of the lists set forth on www.altova.com/list/index.html. Therefore, Altova does not warrant or guarantee the accuracy, reliability, completeness, usefulness, non-infringement of intellectual property rights, or quality of any content on the Altova Mailing List Archive(s), regardless of who originates that content. You expressly understand and agree that you bear all risks associated with using or relying on that content. Altova will not be liable or responsible in any way for any content posted including, but not limited to, any errors or omissions in content, or for any losses or damage of any kind incurred as a result of the use of or reliance on any content. This disclaimer and limitation on liability is in addition to the disclaimers and limitations contained in the Website Terms of Use and elsewhere on the site.