Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.3k views
in Technique[技术] by (71.8m points)

xml - How to replace a node-name with another in Xslt?

Bad wording on the question, sorry about that. Will try to explain what I'm trying to do. Basically I have the output from a search as Xml and in that Xml there is a node like this one:

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

In short, what I need is to replace "<key>" with "<strong>"; ie. highlight the search hits (the key node values are what the user searched for). In the Xslt I do not know what the user searched from, other than querying the Xml -> FIELD[@name='body']/key.

Right now I have some crazy code that will extract whatever is in front of the search term ("Doris"), but that ony works for 1 search term. We need it to do this for multiple terms. The code we use looks like this:

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

What I've been trying to do is to call this code multiple times with the different search terms, but I'm struggeling on how to use the output from the call to the template as input to the next call. In code it would be something like this:

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);   
}

So far I have been unable to do something like this in XSLT, but I'm still a noob so... ;)

Edit: Just to clarify; the output I'm looking for is this:

Somebody named <strong>Doris</strong> and <strong>Arnie</strong>
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The best thing to do in such situations is to recursively copy nodes from input to output and override the nodes that you want to treat differently. The key idea is that the text strings are nodes which can be copied too. Here's an example:

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...