使用xslt创建具有动态名称的变量数组

时间:2019-03-06 16:10:30

标签: xslt xslt-3.0

我想创建一个包含动态名称和模式名称的变量数组。 同样,这些变量是一条逐步处理document-node()的链。 所以不要这样写:

<xsl:variable name="A">
    <xsl:apply-templates mode="A" select="."/>
</xsl:variable>
<xsl:variable name="B">
    <xsl:apply-templates mode="B" select="$A"/>
</xsl:variable>
<xsl:variable name="C">
    <xsl:apply-templates mode="C" select="$B"/>
</xsl:variable>

我想做这样的事情:

<xsl:variable name="mode-names" select="'A', 'B', 'C'"/>

<xsl:variable name="vars">

    <xsl:for-each select="$mode-names">
        <xsl:variable name="pos" select="position()" />     

        <xsl:variable name="{.}">
            <xsl:apply-templates mode="{.}" select="if ($pos=1) then . else $modi[$pos -1]"/>
        </xsl:variable>

    </xsl:for-each>
</xsl:variable>

错误消息:无效的变量名称:无效的QName {{。}}

xslt 3.0

1 个答案:

答案 0 :(得分:1)

目前尚不清楚以后如何使用xsl:variable name="{.}",如果要在变量中存储多个项目,则当然可以使用一系列项目,因此对于您创建您可以使用document-node()*类型的变量来表示各种文档节点,该变量表示一系列文档/文档节点。

因此,使用三个(静态)模式并把每个结果作为项目存储在该变量中的示例将是

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:output indent="yes"/>

  <xsl:mode name="A" on-no-match="shallow-copy"/>

  <xsl:template match="foo" mode="A">
      <bar>
          <xsl:apply-templates mode="#current"/>
      </bar>
  </xsl:template>

  <xsl:mode name="B" on-no-match="shallow-copy"/>

  <xsl:template match="bar" mode="B">
      <whatever>
          <xsl:apply-templates mode="#current"/>
      </whatever>
  </xsl:template>

  <xsl:mode name="C" on-no-match="shallow-copy"/>

  <xsl:template match="text()" mode="C">
      <xsl:value-of select="upper-case(.)"/>
  </xsl:template>

  <xsl:variable name="results" as="document-node()*">
      <xsl:variable name="r1">
          <xsl:apply-templates mode="A"/>
      </xsl:variable>
      <xsl:sequence select="$r1"/>
      <xsl:variable name="r2">
          <xsl:apply-templates select="$r1" mode="B"/>
      </xsl:variable>
      <xsl:sequence select="$r2"/>
      <xsl:apply-templates select="$r2" mode="C"/>
  </xsl:variable>

  <xsl:template match="/">
      <results>
          <xsl:for-each select="$results">
              <result step="{position()}">
                  <xsl:copy-of select="."/>
              </result>
          </xsl:for-each>
      </results>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/3NJ38YX/1

正如我在评论中已经说过的那样,除非在运行时构造整个样式表然后使用transform函数运行它,否则无法在运行时构造模式名称:

<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="#all"
    version="3.0">

    <xsl:param name="mode-names" as="xs:string*" select="'A', 'B', 'C'"/>

    <xsl:param name="stylesheet-template-string" as="xs:string"><![CDATA[
        <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
            xmlns:xs="http://www.w3.org/2001/XMLSchema" version="3.0" exclude-result-prefixes="#all">

            <xsl:mode name="A" on-no-match="shallow-copy"/>

            <xsl:template match="foo" mode="A">
                <bar>
                    <xsl:apply-templates mode="#current"/>
                </bar>
            </xsl:template>

            <xsl:mode name="B" on-no-match="shallow-copy"/>

            <xsl:template match="bar" mode="B">
                <whatever>
                    <xsl:apply-templates mode="#current"/>
                </whatever>
            </xsl:template> 

            <xsl:mode name="C" on-no-match="shallow-copy"/>

            <xsl:template match="text()" mode="C">
                <xsl:value-of select="upper-case(.)"/>
            </xsl:template>            

        </xsl:stylesheet>
    ]]></xsl:param>

    <xsl:param name="stylesheet-template" select="parse-xml($stylesheet-template-string)"/>

    <xsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl"/>

    <xsl:mode name="construct-stylesheet" on-no-match="shallow-copy"/>

    <xsl:variable name="stylesheet">
        <xsl:apply-templates select="$stylesheet-template" mode="construct-stylesheet"/>
    </xsl:variable>

    <xsl:template match="xsl:stylesheet | xsl:transform" mode="construct-stylesheet">
        <xsl:copy>
            <xsl:apply-templates select="@* , node()" mode="#current"/>

            <axsl:variable name="results" as="document-node()*">
                <xsl:iterate select="$mode-names">
                    <axsl:variable name="result-{.}">
                        <axsl:apply-templates select="{if (position() eq 1) then '.' else '$result-' || subsequence($mode-names, position() - 1, 1)}" mode="{.}"/>
                    </axsl:variable>
                    <axsl:sequence select="$result-{.}"/>
                </xsl:iterate>
            </axsl:variable>

            <axsl:template match="/">
                <results>
                    <axsl:for-each select="$results">
                        <result step="{{position()}}">
                            <axsl:copy-of select="."/>
                        </result>
                    </axsl:for-each>
                </results>
            </axsl:template>          
        </xsl:copy>
    </xsl:template>

    <xsl:output indent="yes"/>

    <xsl:template match="/">
        <xsl:sequence
            select="transform(map {
            'source-node' : .,
            'stylesheet-node' : $stylesheet
            })?output"/>
    </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/3NJ38YX/2用于一种模式,而https://xsltfiddle.liberty-development.net/3NJ38YX/3用于不同的模式。

该示例具有一个独立的间接关系,要使用的样式表作为字符串参数传入,但可以或当然可以作为文档节点传入,或使用{{1}从文件解析}的功能相同。