Selecting an item using a variable

Basically, I have a small template that looks like this:

<xsl:template name="templt"> <xsl:param name="filter" /> <xsl:variable name="numOrders" select="count(ORDERS/ORDER[$filter])" /> </xsl:template> 

And I'm trying to call it using

 <xsl:call-template name="templt"> <xsl:with-param name="filter" select="PRICE &lt; 15" /> </xsl:call-template> 

Unfortunately, it seems to evaluate it before the template is called (so false is passed so efficiently). Closing it in quotation marks makes it a string literal, so it doesn't work either. Does anyone know if what I am trying to achieve is possible? If you could shed light on him? Greetings

+4
source share
3 answers

what about the following:

 <?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <xsl:template name="templt"> <xsl:param name="filterNodeName" /> <xsl:param name="filterValue" /> <xsl:variable name="orders" select="ORDERS/ORDER/child::*[name() = $filterNodeName and number(text()) &lt; $filterValue]" /> <xsl:for-each select="$orders"> <xsl:value-of select="."/> </xsl:for-each> </xsl:template> <xsl:template match="/"> <xsl:call-template name="templt"> <xsl:with-param name="filterNodeName" select="'PRICE'" /> <xsl:with-param name="filterValue" select="15" /> </xsl:call-template> </xsl:template> </xsl:stylesheet> 

If you still want to use only one parameter, you can first perform tokenization in the templt template.

+6
source

The marvelous answer is good.

However, it restricts any possible filtering to the name and value of the child.

It is good to know that as a parameter you can pass a function (which is a). This very powerful concept is implemented in FXSL - Functional Programming Library for XSLT. FXSL is completely written in XSLT.

Here is a suitable example using a filter function / template . We pass the filter as a parameter to the template that performs the filtering. A filter can be any code / logic. In this particular case, we pass as a parameter a link to a template that checks whether the number is even. A complete conversion only outputs "num" elements whose value is an even number.

We could easily pass any other filter using exactly the same technique: to filter (un) even numbers, squares, primes, etc.

Remember that you do not need to write the "filter" template itself - it is written once and for all and is provided by the FXSL library. As a result, you usually just use the <xsl: import / "> directive to import the filter template and many other useful functions / templates already provided by FXSL.

Conversion below:

  <xsl: stylesheet version = "1.0" 
 xmlns: xsl = "http://www.w3.org/1999/XSL/Transform"
 xmlns: f = "http://fxsl.sf.net/"
 xmlns: myIsEven = "myIsEven"
 >

   <xsl: import href = "filter.xsl" />

   <! - To be applied on numList.xml ->

   <xsl: output indent = "yes" omit-xml-declaration = "yes" />

   <myIsEven: myIsEven />

   <xsl: template match = "/">
     <xsl: variable name = "vIsEven"
          select = "document ('') / * / myIsEven: * [1]" />

     Filtering by IsEven:
     <xsl: call-template name = "_ filter">
         <xsl: with-param name = "pList" select = "/ * / *" />
         <xsl: with-param name = "pController" select = "$ vIsEven" />
     </ xsl: call-template>

   </ xsl: template>

   <xsl: template name = "myIsEven" mode = "f: FXSL"
     match = "myIsEven: *">
     <xsl: param name = "arg1" />

     <xsl: if test = "$ arg1 mod 2 = 0"> 1 </ xsl: if>
   </ xsl: template>
 </ xsl: stylesheet>

when applied to this source XML document:

  <nums>
   <num> 01 </num>
   <num> 02 </num>
   <num> 03 </num>
   <num> 04 </num>
   <num> 05 </num>
   <num> 06 </num>
   <num> 07 </num>
   <num> 08 </num>
   <num> 09 </num>
   <num> 10 </num>
 </nums>

creates the desired (filtered) result containing only nodes with even values:

  Filtering by IsEven:
 <num> 02 </num>
 <num> 04 </num>
 <num> 06 </num>
 <num> 08 </num>
 <num> 10 </num>

More information on functional programming in XSLT can be found on the FXSL page page , and the library itself can be loaded from the sourceforce project .

To return to a specific problem:

This conversion is:

  <xsl: stylesheet version = "1.0" 
 xmlns: xsl = "http://www.w3.org/1999/XSL/Transform"
 xmlns: f = "http://fxsl.sf.net/"
 xmlns: myFilter = "myFilter"
 >

   <xsl: import href = "filter.xsl" />

   <! - To be applied on Orders.xml ->

   <xsl: output indent = "yes" omit-xml-declaration = "yes" />

   <myFilter: myFilter />

   <xsl: template match = "/">
     <xsl: variable name = "vFilter"
          select = "document ('') / * / myFilter: * [1]" />

     Filtering by PRICE <15:
     <xsl: call-template name = "_ filter">
         <xsl: with-param name = "pList" select = "/ * / *" />
         <xsl: with-param name = "pController" select = "$ vFilter" />
     </ xsl: call-template>

   </ xsl: template>

   <xsl: template name = "myFilter" mode = "f: FXSL"
     match = "myFilter: *">
     <xsl: param name = "arg1" />

     <xsl: if test = "$ arg1 / PRICE & lt; 15"> 1 </ xsl: if>
   </ xsl: template>
 </ xsl: stylesheet>

when applied to this source XML document:

  <ORDERS>
   <ORDER>
     <PRICE> 10 </PRICE>
   </ORDER>
   <ORDER>
     <PRICE> 7 </PRICE>
   </ORDER>
   <ORDER>
       <PRICE> 22 </PRICE>
 </ORDER>
   <ORDER>
       <PRICE> 16 </PRICE>
   </ORDER>
   <ORDER>
       <PRICE> 13 </PRICE>
   </ORDER>
   <ORDER>
       <PRICE> 19 </PRICE>
   </ORDER>
 </ORDERS>  

creates the desired result:

  Filtering by PRICE <15:
 <ORDER>
    <PRICE> 10 </PRICE>
 </ORDER>
 <ORDER>
    <PRICE> 7 </PRICE>
 </ORDER>
 <ORDER>
    <PRICE> 13 </PRICE>
 </ORDER>
+4
source

Use the EXSLT library, in particular the dyn: evaluate function, which can evaluate a string as an XPath expression.

+3
source

All Articles