首页 > 解决方案 > XSLT - 替换变量中的值并将结果保留为节点树

问题描述

我知道这个问题肯定已经被问过很多次了,但这是我今天想要的一个非常具体的答案。

在我的 XSL 中,我有一个变量,我们将其命名为“A”,它包含一个节点树,我想修改这个节点树中的一些特定值。

<xsl:variable name="A">
  <node1>ABC</node1>
  <node2>DEF</node2>
  <node3>
    <node31>ABC</node31>
    <node32>DEF</node32>
  </node3>
</xsl:variable>

对于这个例子,我的目标是用“123”替换这个节点树中等于“ABC”的每个值,并将结果存储在另一个变量中(因为我们无法更新 XSLT 中变量的值)。

这意味着我想要的结果等于:

<xsl:variable name="B">
  <node1>123</node1>
  <node2>DEF</node2>
  <node3>
    <node31>123</node31>
    <node32>DEF</node32>
  </node3>
</xsl:variable>

此外,变量“B”也必须被视为节点树。这意味着我想要做 B/node1 B/node2 等的可能性......

我找到了案例,但它一次考虑了所有文档,但在我的案例中,我已经过滤了一个变量中的结果,并希望将其分开处理。

抱歉,我无法提供真实案例,但这是明智的数据,所以我负担不起。

允许使用 XSLT 2.0 或 3.0。

谢谢你。

标签: xsltxslt-2.0xslt-3.0

解决方案


任何转换都应使用模板实现,使用单独的模式以确保处理不会干扰其余代码:

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

  <xsl:param name="replacements" as="map(xs:string, xs:string)"
    select="map { 'ABC' : '123' }"/>

  <xsl:template match="text()[. = map:keys($replacements)]" mode="replace-value">
      <xsl:value-of select="$replacements(.)"/>
  </xsl:template>

  <xsl:variable name="A">
      <node1>ABC</node1>
      <node2>DEF</node2>
      <node3>
        <node31>ABC</node31>
        <node32>DEF</node32>
      </node3>
  </xsl:variable>

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

https://xsltfiddle.liberty-development.net/ejivdHu

如果要使用参数,可以更改任何apply-templates参数,然后使用隧道参数并将检查移动到要转换的节点的模板中:

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

  <xsl:param name="replacements" as="map(xs:string, xs:string)"
    select="map { 'ABC' : '123' }"/>

  <xsl:template match="text()" mode="replace-value">
      <xsl:param name="replacements" tunnel="yes"/>
      <xsl:value-of
         select="if (map:contains($replacements, .))
                 then $replacements(.)
                 else ."/>
  </xsl:template>

  <xsl:variable name="A">
      <node1>ABC</node1>
      <node2>DEF</node2>
      <node3>
        <node31>ABC</node31>
        <node32>DEF</node32>
      </node3>
  </xsl:variable>

  <xsl:variable name="B">
      <xsl:apply-templates select="$A" mode="replace-value">
          <xsl:with-param name="replacements" tunnel="yes" select="$replacements"/>
      </xsl:apply-templates>
  </xsl:variable>

  <xsl:variable name="C">
      <xsl:apply-templates select="$A" mode="replace-value">
          <xsl:with-param name="replacements" tunnel="yes" select="map { 'DEF' : 'xxx', 'ABC' : 'yyy' }"/>
      </xsl:apply-templates>
  </xsl:variable>

https://xsltfiddle.liberty-development.net/ejivdHu/1


推荐阅读