XSLT - 替换变量中的值并将结果保留为节点树

XSLT - Replace a value in a variable and keep the result as Node Tree

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

在我的 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。

谢谢。

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

  <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