RE: [xsl] filtering elements by single xpath

Subject: RE: [xsl] filtering elements by single xpath
From: "Michael Kay" <mike@xxxxxxxxxxxx>
Date: Wed, 5 Apr 2006 18:12:06 +0100
Try to avoid using copy-of here - copying nodes is expensive and often
unnecessary.

The simplest way is to avoid the inner predicate:

 <xsl:variable
     name="filtered-items"
     select="item[/root/item-filter/allow-items/@with-name = @name]"
 />

Saxon 8.x will do this automatically, but 6.x and other processors will
perform better if you pull the constant expression out of the loop:

<xsl:variable name="names"
select="/root/item-filter/allow-items/@with-name"/>
<xsl:variable
     name="filtered-items"
     select="item[$names = @name]"
 />

Better still is to use keys:

<xsl:key name="k" match="allow-items" use="@with-name"/>

then

select="item[key('k', @name)]"

Michael Kay
http://www.saxonica.com/


> -----Original Message-----
> From: Tomas Kolaci [mailto:kolaci@xxxxxxx] 
> Sent: 05 April 2006 15:46
> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> Subject: [xsl] filtering elements by single xpath
> 
>  Hi!
> 
>  I'm using XSLT 1.1 and Saxon 6.5.3.
> 
>  I have following XML structure:
> 
> <root>
>    <body>
>       <item pos="1" name="n1"/>
>       <item pos="2" name="n2"/>
>       <item pos="3" name="n2"/>
>       <item pos="4" name="n3"/>
>       <item pos="5" name="n4"/>
>    </body>
>    <item-filter>
>       <allow-items with-name="n2"/>
>       <allow-items with-name="n4"/>
>    </item-filter>
> </root>
> 
> and in template:
> 
> <xsl:template match="body">
>    <xsl:variable
>      name="filtered-items"
>      select="item[/root/item-filter/allow-items[@with-name = 
> ???/@name]"
>    />
>    ...
> </xsl:template>
> 
> I'm trying to fill variable filtered-items with elements item 
> with "allowed"
> name (= there is an element /root/item-filter/allow-items 
> with attribute
> @with-name containing same value as item's @name)*, but I 
> don't know how to
> reach current item on ??? position in my select (function 
> current() points
> to current body element).
> 
>  I can handle it by sequential processing (copy of item is 
> good enough for
> my needs):
> 
> <xsl:variable name="filtered-items">
>    <xsl:for-each select="item">
>       <xsl:if
>         test="/root/item-filter/allow-items[@with-name = 
> current()/@name]">
>          <xsl:copy-of select="."/>
>       </xsl:if>
>    </xsl:for-each>
> </xsl:variable>
> 
> but I'm just curious if it is possible to achieve this by 
> single xpath?
> 
>  Thanks in advance!
> 
>  Best regards, Tomas
> 
> *resultant filtered-items content for given example should be:
> 
> <item pos="2" name="n2"/>
> <item pos="3" name="n2"/>
> <item pos="5" name="n4"/>

Current Thread