使用变量选择元素

发布于 2024-07-09 09:20:18 字数 530 浏览 6 评论 0原文

基本上我有一个看起来像这样的小模板:

<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”)将其括在引号中只会使其成为字符串字面意义,所以这也不起作用。 有谁知道我想要实现的目标是否可能? 如果是这样,你能解释一下吗? 干杯

Basically I have a small template that looks like:

<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 < 15" />
</xsl:call-template>

Unfortunately it seems to evaluate it before the template is called (So effectively "false" is being passed in) Enclosing it in quotes only makes it a string literal so that doesn't work either. Does anybody know if what I'm trying to achive is possible? If so could you shed some light on it? Cheers

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦行七里 2024-07-16 09:20:18

下面怎么样:

<?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()) < $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”中进行标记。

how 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()) < $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 a single parameter only, you could tokenize in template 'templt' first.

少女七分熟 2024-07-16 09:20:18

Divo 的回答很好。

但是,它将任何最终过滤限制为指定子项的名称和值。

很高兴知道可以传递一个(相当于一个)函数作为参数。 这个非常强大的概念在 FXSL(XSLT 函数式编程库)中实现。 FXSL 完全是用 XSLT 本身编写的。

这是使用 过滤器函数/模板。 我们将过滤器作为参数传递给执行过滤的模板。 过滤器可以是任何代码/逻辑。 在这种特殊情况下,我们将一个引用作为参数传递给一个检查数字是否为偶数的模板。 完整的转换仅输出那些值为偶数的“num”元素。

我们可以很容易地通过任何其他过滤器,使用完全相同的技术:过滤(不)偶数、平方、质数等。

请注意,这个过滤器不会'不必自己编写“过滤器”模板——它是一次性编写的,并且由 FXSL 库提供。 因此,您通常只需使用即可。 指令导入“过滤器”模板和 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 项目

回到具体问题:

此转换:

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

Divo's answer is a good one.

However, it restricts any eventual filtering to specifying a child's name and value.

It is good to know that one can pass a (what amounts to a) function as a parameter. This very powerful concept is implemented in FXSL -- the Functional Programming Library for XSLT. FXSL is written entirely in XSLT itself.

Here is an appropriate example using the filter function/template. We are passing the filter as a parameter to a template that performs the filtering. The filter can be any code/logic. In this particular case we are passing as parameter a reference to a template that checks if a number is even. The complete transformation outputs only those "num" elements, whose value is an even number.

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

Do note, that one doesn't have to write himself the "filter" template -- it is written once and forever and provided by the FXSL library. As result you typically just uses the <xsl:import/> directive to import the "filter" template and many other useful functions/templates already provided by FXSL.

The transformation 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 on 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>

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

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

More information about Functional Programming in XSLT can be found on the page of FXSL and the library itself can be downloaded from its sourceforce project.

To return to the concrete problem:

This transformation:

<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 < 15">1</xsl:if>
  </xsl:template>
</xsl:stylesheet>

when applied on 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>  

produces the wanted result:

Filtering by PRICE < 15:
<ORDER>
   <PRICE>10</PRICE>
</ORDER>
<ORDER>
   <PRICE>7</PRICE>
</ORDER>
<ORDER>
   <PRICE>13</PRICE>
</ORDER>
话少情深 2024-07-16 09:20:18

使用 EXSLT 库,特别是 dyn:evaluate 函数,它可以评估作为 XPath 表达式的字符串。

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文