Reputation: 1883
I currently have a simple markup which mostly represents HTML.
Below is a snippet of that
<li>Make this <b>Bold</b></li>
I can of course use <xsl:copy-of>
to ensure that the <b>
tag is passed through and is automatically displayed as bold, however I have a problem.
I am using another XSL which checks the markup against a repository of keywords or phrases and if they exist, links are created.
Below is my XSL
<xsl:template name="List" match="li">
<li>
<xsl:call-template name="markup">
<xsl:with-param name="text" select="."/>
<xsl:with-param name="phrases" select="document('../../documents/main/keywords.xml')/keywords/keyword"/>
<xsl:with-param name="first-only" select="false()"/>
</xsl:call-template>
</li>
</xsl:template>
This method prevents any child tags being passed through, however I am unsure as to how I can get around this.
Any help is greatly appreciated! Dan
Upvotes: 1
Views: 134
Reputation: 338316
The problem is that your link-creating template does the wrong thing.
The right thing to do is using the identity template and creating a dedicated template for text node descendants of <li>
elements.
Try this:
<xsl:variable
name="keywords"
select="document('../../documents/main/keywords.xml')/keywords/keyword"
/>
<!-- the identity template does copies of everything not matched otherwise -->
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*" />
</xsl:copy>
</xsl:template>
<!-- text nodes in <li> elements get special treatment -->
<xsl:template match="li//text()">
<xsl:call-template name="markup">
<xsl:with-param name="phrases" select="$keywords"/>
<xsl:with-param name="first-only" select="false()"/>
</xsl:call-template>
</xsl:template>
<!-- marks up the current node -->
<xsl:template name="markup">
<xsl:with-param name="phrases" />
<xsl:with-param name="first-only" select="true()" />
<!-- you can use . here - no need to pass in a $text param -->
</xsl:template>
The identity template is the key to successfully solving problems like this one. It handles copying the <li>
and the <b>
transparently.
<xsl:template name="List">
. This is "push style" XSLT, i.e. it's imperative and often leads to pretty clumsy results.<xsl:template match="li//text()">
pulls nodes out of the stream and does something more complex than just copying them. This is "pull style" XSLT, i.e. template matching. It usually is easier to handle and produces cleaner XSLT code.<li>
elements, of course. Just change the match expression to affect other nodes.Say you want to turn all <b>
nodes into <strong>
without disrupting any other templates. With pull style, this is as easy as this:
<xsl:template match="b">
<strong>
<xsl:apply-templates select="node() | @*" />
<strong>
</xsl:template>
Also note that the current node does not change when you do <xsl:call-template>
. Therefore there is no need to pass in the current node to a called template.
Upvotes: 1