【问题标题】:XSLT - Replace a value in a variable and keep the result as Node TreeXSLT - 替换变量中的值并将结果保留为节点树
【发布时间】:2019-12-13 09:05:40
【问题描述】:

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

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

谢谢。

【问题讨论】:

    标签: xslt xslt-2.0 xslt-3.0


    【解决方案1】:

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

      <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

    【讨论】:

    • 对不起,我忘记了一件事,那就是匹配的过滤器可以改变。在您的情况下, $replacements 被定义为全局参数
    • @Farolink,看看第二个建议是否有助于满足您的新要求。问一个新问题可能会更好。
    • 我的救命恩人。十分感谢。它正在工作。仅就我个人的知识而言,我有点了解该模式的作用,但即使在互联网上查看隧道功能,我也没有得到它,它在做什么?谢谢!
    • @Farolink,使用 XSLT 1,如果你想从例如传递参数从根节点到叶节点,您必须确保在每个级别/每次使用xsl:apply-templates 时明确传递它们。在 XSLT 2 和 3 中,使用隧道参数,您可以在某个级别传递它们并进一步接收它们,处理器将负责将它们传递到您没有明确传递它们的地方。请参阅w3.org/TR/xslt-30/#tunnel-params 或您最喜欢的 XSLT 2/3 教科书中有关它们的部分。
    • 我最后还有一个问题,返回类型被认为是字符串而不是节点树。例如,当我尝试执行 时,它什么也不返回。当我用 xsl:message 显示它时,它看起来不错'
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-13
    • 1970-01-01
    • 2018-05-27
    • 1970-01-01
    • 1970-01-01
    • 2021-04-29
    相关资源
    最近更新 更多