4

I want to usw the XSLT replace function to replace words in a text with

<strong>word</strong>.

I wrote the following template:

<xsl:template name="make-bold">
  <xsl:param name="text"/>
  <xsl:param name="word"/>
  <xsl:variable name="replacement">
     <strong><xsl:value-of select="$word"/></strong>
  </xsl:variable>
  <xsl:value-of select="replace($text, $word,  $replacement )" />
</xsl:template>

Unfortunately, and are not rendered, althoug the rest works.

Could anyone help me?

Best, Suidu

2 Answers 2

6

Well the replace function http://www.w3.org/TR/xpath-functions/#func-replace takes a string and returns a string. You seem to want to create an element node, not a simple string. In that case using analyze-string http://www.w3.org/TR/xslt20/#analyze-string instead of replace could help.

Here is a sample XSLT 2.0 stylesheet:

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="xs"
  version="2.0">

  <xsl:output method="html" indent="no"/>

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

  <xsl:template match="p">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates select="text()" mode="wrap">
        <xsl:with-param name="words" as="xs:string+" select="('foo', 'bar')"/>
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="text()" mode="wrap">
    <xsl:param name="words" as="xs:string+"/>
    <xsl:param name="wrapper-name" as="xs:string" select="'strong'"/>
    <xsl:analyze-string select="." regex="{string-join($words, '|')}">
      <xsl:matching-substring>
        <xsl:element name="{$wrapper-name}">
          <xsl:value-of select="."/>
        </xsl:element>
      </xsl:matching-substring>
      <xsl:non-matching-substring>
        <xsl:value-of select="."/>
      </xsl:non-matching-substring>
    </xsl:analyze-string>
  </xsl:template>

</xsl:stylesheet>

When you run that with an XSLT 2.0 processor like Saxon 9 against the following input sample

<html>
  <body>
    <p>This is an example with foo and bar words.</p>
  </body>
</html>

the output is as follows:

<html>
  <body>
    <p>This is an example with <strong>foo</strong> and <strong>bar</strong> words.</p>
  </body>
</html>
Sign up to request clarification or add additional context in comments.

2 Comments

+1 Right XSLT 2.0 answer. But I think the p matching rule is not necessary. If you want to apply the wraper rule only to p's text node child (or even better, descendants) you could use this patter p/text() (or p//text())
Thank you, Martin and Alejandro. The suggested solution works well! Suidu
0

hmm is is because here it its the string value that is replaced, you might try to use the node set?

i cannot test as i dont use xslt 2.0 but you might try a recursive template ie

<xsl:template match="yourtextelement">
   <xsl:call-template name="MaketextStrong">
</xsl:template>

<xsl:template name="MaketextStrong">
   <xsl:param name="text" select="."/>
   <xsl:choose>
   <xsl:when test="contains($text, 'texttomakestrong')">
      <xsl:value-of select="substring-before($text, 'texttomakestrong')"/>
      <strong>texttomakestrong</strong>
      <xsl:call-template name="break">
          <xsl:with-param name="text" select="substring-after($text,
'texttomakestrong')"/>
      </xsl:call-template>
   </xsl:when>
   <xsl:otherwise>
 <xsl:value-of select="$text"/>
   </xsl:otherwise>
   </xsl:choose>
</xsl:template>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.