Выбор элемента с использованием переменной - PullRequest
4 голосов
/ 28 ноября 2008

В основном у меня есть небольшой шаблон, который выглядит так:

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

И я пытаюсь вызвать его с помощью

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

К сожалению, кажется, что он оценивает его до того, как шаблон вызывается (так эффективно передается "false"). Заключение в кавычки делает его только строковым литералом, так что тоже не работает Кто-нибудь знает, возможно ли то, что я пытаюсь достичь? Если так, то не могли бы вы пролить свет на это? Приветствия

Ответы [ 3 ]

6 голосов
/ 28 ноября 2008

как насчет следующего:

<?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>

Если вы все еще хотите использовать только один параметр, вы можете сначала использовать токен в шаблоне 'templt'.

4 голосов
/ 29 ноября 2008

Ответ Диво хороший.

Однако любая возможная фильтрация ограничивается указанием имени и значения дочернего элемента.

Хорошо знать, что можно передать (что равно a) функцию в качестве параметра . Эта очень мощная концепция реализована в FXSL - библиотеке функционального программирования для XSLT. FXSL полностью написан на самом XSLT.

Вот соответствующий пример использования функции фильтра / шаблона . Мы передаем фильтр в качестве параметра шаблону, который выполняет фильтрацию. Фильтр может быть любым кодом / логикой. В этом конкретном случае мы передаем в качестве параметра ссылку на шаблон, который проверяет, является ли число четным. Полное преобразование выводит только те «num» элементы, значение которых является четным числом.

Мы могли бы очень легко пропустить любой другой фильтр , используя точно такую ​​же технику: фильтровать (не) четные числа, квадраты, простые числа, ... и т. Д.

Обратите внимание, что самому шаблону «фильтра» не нужно писать - он пишется раз и навсегда и предоставляется библиотекой FXSL. В результате вы обычно просто используете директиву для импорта шаблона «filter» и многих других полезных функций / шаблонов, уже предоставленных FXSL.

Преобразование ниже:

<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>

при применении к этому исходному документу XML:

<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>

дает желаемый (отфильтрованный) результат, содержащий только узлы с четными значениями:

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

Более подробную информацию о функциональном программировании в XSLT можно найти на странице FXSL , а саму библиотеку можно загрузить из ее sourceforce project .

Чтобы вернуться к конкретной проблеме:

Это преобразование:

<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>

при применении к этому исходному документу XML:

<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>  

дает желаемый результат:

Filtering by PRICE < 15:
<ORDER>
   <PRICE>10</PRICE>
</ORDER>
<ORDER>
   <PRICE>7</PRICE>
</ORDER>
<ORDER>
   <PRICE>13</PRICE>
</ORDER>
3 голосов
/ 28 ноября 2008

Используйте библиотеку EXSLT, в частности, функцию dyn :valu , которая может оценивать строку как выражение XPath.

...