I want to add acronyms to an HTML text using xslt:analyze-string. The problem: in my HTML text are tags such as
<strong>some text</strong>
that are treated as XML nodes. When I apply xslt:analyze-string these nodes are converted to strings - the tags are stripped away. Also in my recursive XSLT stylesheet the acronyms that are already inserted are stripped away, too.
My question: is there a trick to prevent xslt:analyze-string of transforming the HTML nodes to strings and preserve the HTML tags?
Here's my example:
Stylesheet:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns="http://www.w3.org/1999/xhtml" exclude-result-prefixes="xhtml" >
<xsl:template match="/">
<div>
<xsl:call-template name="insert-acronyms">
<xsl:with-param name="text" select="/doc/div"/>
<xsl:with-param name="acronyms" select="/doc/dictionary/acronym"/>
</xsl:call-template>
</div>
</xsl:template>
<xsl:template name="insert-acronyms">
<xsl:param name="text" as="node()*"/>
<xsl:param name="acronyms"/>
<xsl:choose>
<xsl:when test="$acronyms">
<xsl:call-template name="insert-acronyms">
<xsl:with-param name="acronyms" select="$acronyms[position() > 1]"/>
<xsl:with-param name="text">
<xsl:call-template name="replace-words">
<xsl:with-param name="text" select="$text"/>
<xsl:with-param name="name" select="$acronyms[1]/name"/>
<xsl:with-param name="description" select="$acronyms[1]/description"/>
</xsl:call-template>
</xsl:with-param>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="replace-words">
<xsl:param name="text" />
<xsl:param name="name" />
<xsl:param name="description" />
<xsl:analyze-string select="$text" regex="{concat('(^|\W)(', string-join($name, '|'), ')(\W|$)')}">
<xsl:matching-substring>
<xsl:value-of select="regex-group(1)"/>
<xsl:element name="acronym">
<xsl:attribute name="title"><xsl:value-of select="$description"/></xsl:attribute>
<xsl:value-of select="regex-group(2)"/>
</xsl:element>
<xsl:value-of select="regex-group(3)"/>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
</xsl:stylesheet>
Source:
<?xml version="1.0" encoding="UTF-8"?>
<doc>
<dictionary>
<acronym>
<name>WWW</name>
<description>The World Wide Web</description>
</acronym>
<acronym>
<name>HTML</name>
<description>The HyperText Markup Language</description>
</acronym>
</dictionary>
<div>
<p>In the <strong>WWW</strong> you can find a lot of <em>HTML</em> documents.</p>
</div>
</doc>
Result of the transformation (strong and em-tags are stripped away, only one acronym is inserted because the other is stripped away, too):
<?xml version="1.0" encoding="UTF-8"?>
<div> In the WWW you can find a lot of <acronym title="The HyperText Markup Language">HTML</acronym> documents. </div>
The provided code is unnecessarily complicated. The main problem is trying to create an acronym one-at-a-time and also unnecessarily trying recursive processing.
Here is a simpler and logical, non-recursive solution:
When this transformation is applied on the provided XML document:
the wanted, correct result is produced:
xsl:analyze-string
works on strings. Rather than trying to apply to any/all nodes, just have it apply to thetext()
nodes.Try changing your stylesheet to (untested):