【问题标题】:Dynamic for-each based on function arguments in XSLT v2.0基于 XSLT v2.0 中函数参数的动态 for-each
【发布时间】:2013-06-26 01:58:03
【问题描述】:

我想创建一个通用的 XSLT 2.0 函数,它可以像这样在 xml 上运行:

<?xml version="1.0"?>
<foo xmlns:my="http://meohmy.org" xmlns:yours="http://meohmy2.org">
    <yours:pet my:type="dog" my:color="red">Cindy</yours:pet>
    <yours:pet my:type="cat">Felix</yours:pet>
    <yours:pet my:type="cat" my:color="green">Pai Mei</yours:pet>
</foo> 

并给出这样的函数签名:

my:doit('item',/foo/yours:/pet,@my:color)

(第一个参数是标签,第二个是我要报告的节点集,第三个是我要为第二个参数的节点集中的每个节点输出的值,无论它是否有)。

我希望它返回这样的数据:

info=red;;green

请注意,我想要一个与没有第三个参数的元素相对应的空占位符,并且顺序很重要。

由于我在样式表中经常这样做(出于不同原因数十次),因此函数似乎是一种自然的方式。到目前为止,这是我想出的......

<?xml version="1.0"?>
<xsl:stylesheet version="2.0" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:my="http://meohmy.org" 
    xmlns:yours="http://meohmy2.org">

   <xsl:template match="/">
       <xsl:value-of select="my:doit('item',/foo/yours:pet,@my:color)"/>
   </xsl:template>

   <xsl:function name="my:doit" as="xs:string?">
      <xsl:param name="item" as="xs:string"/>
      <xsl:param name="value"/>
      <xsl:param name="subvalue"/>
      <xsl:if test="$value">
        <xsl:value-of>
             <xsl:value-of select="$item"/>
             <xsl:text>=</xsl:text>
             <xsl:for-each select="$value">
                  <xsl:value-of select="current()/$subvalue"/>
              <xsl:if test="position() != last()">
                   <xsl:text>;</xsl:text>
              </xsl:if>
             </xsl:for-each>
        </xsl:value-of>
    </xsl:if>
  </xsl:function>
</xsl:stylesheet>

但是,当我这样做时,我会从函数 doit() 中获得以下值:

item=;;

这表明&lt;xsl:value-of select="current()/$subvalue"/&gt; 在样式表中不正确。我很接近,我能感觉到;> 有什么建议吗?

谢谢!

【问题讨论】:

    标签: function xslt dynamic xslt-2.0 value-of


    【解决方案1】:

    在您的示例中,您认为您将 XPath 表达式作为第三个参数传递,但事实并非如此 - 您正在传递它的值。

    在 XPath 3.0 中有一个干净的解决方案来解决这个问题:您可以传递一个函数作为第三个参数。所以调用变成了

    select="my:doit('item', /foo/yours:pet, function($e){$e/@my:color})"
    

    实现变成了

          <xsl:function name="my:doit" as="xs:string?">
              <xsl:param name="item" as="xs:string"/>
              <xsl:param name="value" as="element()*/>
              <xsl:param name="subvalue" as="function(element()) as xs:string?"/>
              <xsl:if test="$value">
                <xsl:value-of>
                     <xsl:value-of select="$item"/>
                     <xsl:text>=</xsl:text>
                     <xsl:value-of select="$value ! $subvalue(.)" separator=";"/>
                </xsl:value-of>
            </xsl:if>
          </xsl:function>
    

    如果您不能使用 XPath 3.0(上述方法适用于 Saxon-PE 9.5),那么替代方法是 (a) 使用 Dimitre Novatchev 的 FXSL 库,它在 XSLT 2.0 中模拟高阶函数,或者(b) 不传递函数,而是传递字符串形式的 XPath 表达式,并使用 xx:eval() 扩展函数动态评估表达式 - 许多处理器提供这样的扩展,但它不是标准语言.

    (注意,在 XPath 3.0 中,A!B 的含义与“for $x in A return $x/B”基本相同)

    【讨论】:

    • 谢谢!我将升级到 Xpath 3.0,但我还发现 Saxon 的动态函数可以解决问题(但这需要 Saxon 的 PE 或 EE(付费)版本。
    【解决方案2】:

    试试这个样式表

        <?xml version="1.0"?>
        <xsl:stylesheet version="2.0" 
            xmlns:xs="http://www.w3.org/2001/XMLSchema" 
            xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
            xmlns:my="http://meohmy.org" 
            xmlns:yours="http://meohmy2.org">
    
           <xsl:template match="/">
               <xsl:value-of select="my:doit('item',/foo/yours:pet,'my:color')"/>
           </xsl:template>
    
           <xsl:function name="my:doit" as="xs:string?">
              <xsl:param name="item" as="xs:string"/>
              <xsl:param name="value"/>
              <xsl:param name="subvalue"/>
              <xsl:if test="$value">
                <xsl:value-of>
                     <xsl:value-of select="$item"/>
                     <xsl:text>=</xsl:text>
                     <xsl:for-each select="$value">
                          <xsl:value-of select="current()/attribute()[name() = $subvalue]"/>
                      <xsl:if test="position() != last()">
                           <xsl:text>;</xsl:text>
                      </xsl:if>
                     </xsl:for-each>
                </xsl:value-of>
            </xsl:if>
          </xsl:function>
        </xsl:stylesheet>
    

    它给了我结果

    item=red;;green
    

    【讨论】:

    • 是的,但我认为它不像 OP 想要的那样通用。它只允许将属性名称作为第三个参数传递,而不是任意 XPath 表达式。
    • 我完全同意,事实并非如此。但我不确定在 xlts 2.0 中是否可以像 OP 想要的那样制作通用解决方案。所以我做了一些简化。当然,如果有更好的解决方案,我想学习如何去做,因为有时它可能很有用。
    • 是的,我想我已经达到了 XSLT 2.0 的极限。不过谢谢!
    猜你喜欢
    • 2020-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-16
    • 1970-01-01
    • 2015-07-30
    • 2020-04-07
    • 1970-01-01
    相关资源
    最近更新 更多