代码之家  ›  专栏  ›  技术社区  ›  shawn

XSLT 3.0在应用模板中使用变量进行动态选择?

  •  3
  • shawn  · 技术社区  · 6 年前

    我想将模板应用于一组节点,其中 select path是一个变量。我用的是萨克森HE 9.8(很棒的lib!)

    我正在努力实现以下目标

    <variable name="x" select="string('baz')"/>
    <xsl:apply-templates select="foo/bar/$x"/>
    

    这似乎不起作用。是否有语法允许我为此动态构造select XPath apply-templates 指示或者,是否有其他技术可以动态实现这种效果?我甚至试着把这个推到我的 <xsl:template match=foo/bar/$x> 但运气不好。

    我的动机是在我的应用程序中变量值来自 单独的配置文件 。根据配置,我需要运行与配置字符串驱动的特定路径段匹配的模板。。。

    2 回复  |  直到 6 年前
        1
  •  2
  •   Martin Honnen    6 年前

    如果您声明 static parameter <xsl:param name="x" static="yes" as="xs:string" select="'baz'"/> ,然后使用 shadow attribute 形式为 _select="foo/bar/{$x}" 您甚至可以动态构造路径,但只能在编译XSLT时进行。

    在静态参数中,您当然可以拉入配置文件并使用其中的值:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        version="3.0">
    
      <xsl:param name="config-uri" static="yes" as="xs:string" select="'https://martin-honnen.github.io/xslt/2018/config-example1.xml'"/>
      <xsl:param name="config-doc" static="yes" as="document-node()" select="doc($config-uri)"/>
    
      <xsl:mode on-no-match="shallow-copy"/>
    
      <xsl:template match="item[@type = 'foo']">
          <xsl:copy>
              <xsl:value-of _select="{$config-doc/map/from[@key = 'foo']}"/>
          </xsl:copy>
      </xsl:template>
    
      <xsl:template match="item[@type = 'bar']">
          <xsl:copy>
              <xsl:value-of _select="{$config-doc/map/from[@key = 'bar']}"/>
          </xsl:copy>
      </xsl:template>
    
    </xsl:stylesheet>
    

    https://xsltfiddle.liberty-development.net/6qVRKvX/1

    transform 功能( https://www.w3.org/TR/xpath-functions/#func-transform )运行生成的XSLT。这种方法的优点是它适用于Saxon 9.8 HE xsl:evaluate 不支持:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:axsl="http://www.w3.org/1999/XSL/Transform-alias"
        exclude-result-prefixes="axsl"
        version="3.0">
    
      <xsl:param name="config-uri" as="xs:string" select="'https://martin-honnen.github.io/xslt/2018/config-example1.xml'"/>
      <xsl:param name="config-doc" as="document-node()" select="doc($config-uri)"/>
    
      <xsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl"/>
    
      <xsl:variable name="generated-xslt">
          <axsl:stylesheet version="3.0">
              <axsl:mode on-no-match="shallow-copy"/>
              <xsl:for-each select="$config-doc/map/from">
                  <axsl:template match="item[@type = '{@key}']">
                      <axsl:copy>
                          <axsl:value-of select="{.}"/>
                      </axsl:copy>
                  </axsl:template>
              </xsl:for-each>
          </axsl:stylesheet>
      </xsl:variable>
    
      <xsl:mode on-no-match="shallow-copy"/>
    
      <xsl:template match="/">
          <xsl:sequence 
            select="transform(map {
                'source-node' : .,
                'stylesheet-node' : $generated-xslt
              })?output"/>
      </xsl:template>
    
    </xsl:stylesheet>
    

    https://xsltfiddle.liberty-development.net/6qVRKvX/2

        2
  •  1
  •   Mads Hansen    6 年前

    如果变量始终是表示元素名称的简单字符串值,那么一个选项是对元素进行更一般的匹配,然后在谓词中使用字符串变量来筛选元素名称的匹配:

    <xsl:apply-templates select="foo/bar/*[local-name() = $x]"/>
    

    使用Saxon PE或Saxon EE,您可以利用 xsl:evaluate 然后这样做:

    <xsl:variable name="var" as="node()*">
      <xsl:evaluate xpath="concat('foo/bar/',$x)" context-item="."/>
    </xsl:variable>
    <xsl:apply-templates select="$var"/>