代码之家  ›  专栏  ›  技术社区  ›  noocyte

如何用XSLT中的另一个节点名替换节点名?

  •  3
  • noocyte  · 技术社区  · 15 年前

    这个问题措辞不好,对不起。我会尽力解释我想做什么。 基本上,我的搜索结果是XML,在XML中有一个像这样的节点:

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

    简而言之,我需要将“<key>”替换为“<strong>”,即突出显示搜索结果(关键节点值是用户搜索的结果)。在XSLT中,除了查询xml->字段[@name='body']/key之外,我不知道用户从中搜索了什么。

    现在我有一些疯狂的代码可以提取搜索词(“Doris”)前面的任何内容,但是这个ony只适用于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>
    
    3 回复  |  直到 15 年前
        1
  •  10
  •   Rich    15 年前

    在这种情况下,最好的做法是递归地将节点从输入复制到输出,并覆盖您希望以不同方式处理的节点。关键思想是文本字符串也是可以复制的节点。下面是一个例子:

    <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>
    
        2
  •  2
  •   Chris Dail    15 年前

    这应该能满足你的需要。它使用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>
    
        3
  •  1
  •   xcut    15 年前

    为什么不能用“强”元素替换“关键”元素呢?最好不要过于冲动地思考这个问题。

    <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>
    

    还是我误解了你?