Reputation: 8177
I need to highlight the two first words in a string (HTML header) with red by adding a CSS class, and tokenize
is what I'm looking at right now. How exactly can this be done? If possible at all.
Some pseudo code:
<xsl:for-each select="tokenize(title, '\s+')">
// ......
<xsl:attribute name="class">
<xsl:text>className</xsl:text>
</xsl:attribute>
</xsl:for-each>
How do I pick out each word in the result?
Though, tokenize may not be the solution. Any help appreciated!
Upvotes: 2
Views: 2348
Reputation: 163322
The disadvantage of using tokenize() is that you lose the delimiters between tokens. A better solution here is xsl:analyze-string:
<xsl:analyze-string select="title" regex="\s+ (or whatever)">
<xsl:matching-substring><xsl:value-of select="."/></xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:choose>
<xsl:when test="position() le 4">
<span class="xxxx"><xsl:value-of select="."/></span>
</xsl:when>
<xsl:otherwise><xsl:value-of select="."/></xsl:otherwise>
</xsl:choose>
</xsl:non-matching-substring>
</xsl:analyze-string>
If you use a regex that allows for punctuation between words, this ensures that the punctuation will not be lost. You could also reverse the test and have a regex that matches words rather than interword delimiters.
The position() le 4 test allows for the fact that the sequence might start with either a word or an inter-word delimiter.
Upvotes: 1
Reputation: 243449
You are close. Here is a complete transformation:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/*">
<h1>
<xsl:variable name="vWords" select="tokenize(., '\s+')"/>
<span class="className">
<xsl:value-of select="$vWords[not(position() gt 2)]" separator=" "/>
<xsl:text> </xsl:text>
</span>
<xsl:value-of select="$vWords[position() gt 2]" separator=" "/>
</h1>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on this XML document:
<t>Red cat and a mouse</t>
the wanted, correct result is produced:
<h1><span class="className">Red cat </span>and a mouse</h1>
Upvotes: 1
Reputation: 70618
It is possible to use tokenize here, especially if you wanted to cope with other word separators other than single spaces (the second argument of tokenize allows a regular expression to be specified.
Anyway, in your case, it might be worth assigning the results of tokenize to a variable, and then taking different action for the first two words. Try the following XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/*">
<h1>
<xsl:variable name="words" select="tokenize(title, ' ')"/>
<span class="className">
<xsl:value-of select="concat($words[1], ' ', $words[2])"/>
</span>
<xsl:for-each select="$words[position() > 2]">
<xsl:value-of select="concat(' ', .)"/>
</xsl:for-each>
</h1>
</xsl:template>
</xsl:stylesheet>
When applied to this XML as an example
<data>
<title>This is a test</title>
</data>
The following is output
<h1>
<span class="className">This is</span> a test
</h1>
Upvotes: 1