0
votes

In relation to my question

position() function returns the position of actual node in whole document , how to get the position with respect to selected nodes. Lets say I have list of 100 cities and I exclude 10 based on given filter list (please see the question) now the I I want to get the counting based on the selected nodes not the original document positions .

In simple terms this is a counter/increment issue as I see counter are not possible . How could we create or use existing function to like position() to get the position of node in selected nodes.

I hope my question is clear .

edit example scenario

  <xsl:template match="/">
    <xsl:apply-templates select="db:databaseChangeLog/db:changeSet[*[1][($excludes eq '' or not(@tableName = tokenize($excludes, ',')))]]"/> 
  </xsl:template>

   <xsl:template match="db:changeSet">
      ...
   </xsl:template>

Where I am selecting parent node based on the child node attribute name.

2
Maybe this answer will help you?Ben L

2 Answers

1
votes

I think it would be better to use xsl:number. With xsl:number, you should be able to exclude elements much easier.

Here's a small example that shows results from both position() and xsl:number for comparison.

XML Input

<cities>
    <city>City One</city>
    <city>City Two</city>
    <city>City Three</city>
    <city>City Four</city>
    <city>City Five</city>
    <city>City Six</city>
    <city>City Seven</city>
    <city>City Eight</city>
    <city>City Nine</city>
    <city>City Ten</city>
</cities>

XSLT 2.0 (I think 2.0 is safe to assume since the question is tagged saxon and you used tokenize in your comment.)

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

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

    <xsl:variable name="exclude" select="('City Three','City Six','City Nine')"/>

    <xsl:template match="city[not(.=$exclude)]">
        <city position="{position()}">
            <xsl:attribute name="number">
                <xsl:number count="city[not(.=$exclude)]"/>
            </xsl:attribute>
            <xsl:value-of select="."/>
        </city>
    </xsl:template>

    <xsl:template match="city"/>

</xsl:stylesheet>

Output

<cities>
   <city position="1" number="1">City One</city>
   <city position="2" number="2">City Two</city>
   <city position="4" number="3">City Four</city>
   <city position="5" number="4">City Five</city>
   <city position="7" number="5">City Seven</city>
   <city position="8" number="6">City Eight</city>
   <city position="10" number="7">City Ten</city>
</cities>
1
votes

Your description of the position function is wrong. See http://www.w3.org/TR/xslt20/#focus, in particular "The context position is the position of the context item within the sequence of items currently being processed. It changes whenever the context item changes. When an instruction such as xsl:apply-templates or xsl:for-each is used to process a sequence of items, the first item in the sequence is processed with a context position of 1, the second item with a context position of 2, and so on.] The context position is returned by the XPath expression position()".

For instance if we have <xsl:apply-templates select="cities/city[not(@abbr = $skip/abbr)]"/> and we use the position function in the template matching city elements as in e.g.

<xsl:template match="city">
  <xsl:copy>
    <xsl:value-of select="position()"/>
  </xsl:copy>
</xsl:template>

we will get <city>1</city><city>2</city> and so on.