【问题标题】:How to replace a node-name with another in Xslt?如何在 Xslt 中用另一个节点名替换节点名?
【发布时间】:2009-12-18 14:04:31
【问题描述】:

这个问题的措辞不好,对此感到抱歉。将尝试解释我正在尝试做的事情。 基本上,我将搜索的输出作为 Xml,在该 Xml 中有一个像这样的节点:

<FIELD NAME="body">
  Somebody named 
  <key>Doris</key> 
  and 
  <key>Arnie</key> 
</FIELD>

简而言之,我需要将“”替换为“”; IE。突出显示搜索结果(关键节点值是用户搜索的内容)。在 Xslt 中,除了查询 Xml -> FIELD[@name='body']/key 之外,我不知道用户搜索了什么。

现在我有一些疯狂的代码可以提取搜索词(“Doris”)前面的任何内容,但仅适用于 1 个搜索词。我们需要它来为多个术语执行此操作。我们使用的代码如下所示:

  <xsl:template name="highlighter">
    <xsl:param name="text"/>
    <xsl:param name="what"/>

    <xsl:choose>
      <xsl:when test="contains($text, $what) and string-length($what) &gt; 0">
        <xsl:variable name="before" select="substring-before($text, $what)"/>
        <xsl:variable name="after" select="substring-after($text, $what)"/>
        <xsl:variable name="real-before" select="substring($text, 1, string-length($before))"/>
        <xsl:variable name="real-what" select="substring($text, string-length($before) + 1, string-length($what))"/>
        <xsl:variable name="real-after" select="substring($text, string-length($before) + string-length($what) + 1)"/>
        <xsl:value-of select="$real-before"/>

        <strong>
          <xsl:value-of select="$real-what"/>
        </strong>

        <xsl:call-template name="highlighter">
          <xsl:with-param name="text" select="$real-after"/>
          <xsl:with-param name="what" select="$what"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$text"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

我一直在尝试使用不同的搜索词多次调用此代码,但我正在努力研究如何将调用模板的输出用作下一次调用的输入。在代码中会是这样的:

string body = doc.SelectSingleNode("FIELD[@NAME='body']");
NodeCollection nodes = doc.SelectNodes("FIELD[@NAME='body']/key");
foreach (var node in nodes) {
    body = hightlighter(body, node.InnerText);   
}

到目前为止,我一直无法在 XSLT 中做这样的事情,但我还是个菜鸟,所以...... ;)

编辑:只是为了澄清;我正在寻找的输出是这样的:

Somebody named <strong>Doris</strong> and <strong>Arnie</strong>

【问题讨论】:

    标签: xml xslt


    【解决方案1】:

    在这种情况下,最好的做法是递归地将节点从输入复制到输出,并覆盖您想要区别对待的节点。关键思想是文本字符串也是可以复制的节点。这是一个例子:

    <xsl:template match="key">
        <strong>
            <xsl:apply-templates select="@*|node()"/>
        </strong>
    </xsl:template>
    
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    

    【讨论】:

    • 这看起来像 Chris Dali 的答案...如果我使用 "" 将模板全部应用我得到的是粗体的“KEY”节点的值,这不是我想要的......我需要来自“FIELD”节点的所有内容。
    • 尝试只选择 FIELD[@NAME='body'] 甚至 FIELD 或 /
    • 你是个传奇! :) 但是您的 Xslt 中有一个错字;应用模板不允许“匹配”;我相信它应该是“选择”。当我使用“FIELD [NAME ='body']”时它起作用了。 :) 谢谢!!
    • 对不起。我现在已经修正了错字。
    • 不客气。另请参阅我在 cmets 中对 Chris 版本的进一步解释。
    【解决方案2】:

    这应该可以满足您的需要。它使用apply模板而不是调用模板,更多的是解决这个问题的功能性方法。

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
        <!-- Template to match your 'key' and replace with strong -->
        <xsl:template match="FIELD[@name='body']/key">
            <strong><xsl:apply-templates select="@*|node()"/></strong>
        </xsl:template>
    
        <!-- Template to match all nodes, copy them and then apply templates to children. -->
        <xsl:template match="@*|node()">
          <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
          </xsl:copy>
        </xsl:template>
    </xsl:stylesheet>
    

    【讨论】:

    • 嗯...我如何“调用”第一个模板?我或许应该提一下,我已经有一个相当大的 XSLT,我需要在将父节点与“FIELD”匹配的模板中进行此替换。
    • 第二个模板匹配文档中的所有节点并简单地生成它们的副本。第一个模板与您要查找的特定字段/键匹配,并将其替换为 。此模式通常用于使输出 XML 文档成为原始文档的副本。
    • 对不起,我完全没听懂最后的评论...菜鸟,请多多包涵)
    • 当您在节点或属性上应用模板时,XSLT 处理器将寻找最具体的匹配项。在所有情况下,除了处理键时,最具体的匹配将是第二个模板,它只是将当前节点编码到输出,然后递归地将模板应用于其所有子节点或属性。如果在 name="body" 的字段中没有任何键,那么这只会将整个输入文档复制到输出。但是,当处理器遇到键时,它会在输出中创建一个新的“强”元素,然后移动到键的...
    • ...children,也将它们添加到输出中。最终结果是输入中所有适当的“关键”元素都转换为输出中的“强”元素,而其他所有内容都保持不变(包括文本节点)。
    【解决方案3】:

    为什么不能用“STRONG”元素替换“KEY”元素?最好不要想得太迫切。

    <xsl:template match="FIELD[@NAME='body']">
      <xsl:apply-templates/>
    <xsl:template>
    
    <xsl:template match="key">
      <strong>
      <xsl:apply-templates/>
      <strong>
    </xsl:template>
    
    <xsl:template match="text()">
      <xsl:copy-of select="."/>
    </xsl:template>
    

    还是我误会了你?

    【讨论】:

    • 嗯...我如何“调用”第一个模板?我尝试过:“” 但这似乎不起作用...
    • 澄清一下;我正在寻找的输出是:Somebody named Doris and Arnie
    • 模板无论如何都应该匹配,除非您更改了默认模板行为:样式表应该递归 XML 文件,直到找到节点。您的 XML 文件有命名空间吗?您是否在样式表中正确绑定了命名空间?
    猜你喜欢
    • 1970-01-01
    • 2014-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多