This is the mail archive of the
xsl-list@mulberrytech.com
mailing list .
Re: Char node-type
- To: Richard Light <richard at light dot demon dot co dot uk>
- Subject: Re: Char node-type
- From: Jeni Tennison <mail at jenitennison dot com>
- Date: Thu, 23 Nov 2000 11:21:20 +0000
- CC: xsl-list at mulberrytech dot com
- Organization: Jeni Tennison Consulting Ltd
- References: <lEXvRDAn$MH6EwMs@light.demon.co.uk>
- Reply-To: xsl-list at mulberrytech dot com
Richard,
> Since the translate function only deals with one-to-one character
> mappings, we have written a template to process text() nodes which
> processed the first character, then calls itself recursively to
> process the rest of the string. This works fine so long as you don't
> have more than about 600 characters in a single element - with a
> long enough string you get stack overflows.
The way that I usually do this is to define a set of replacements that
I want to have made:
<xsl:variable name="replacements-rtf">
<replace>
<from><</from>
<to><span class="entity">&lt;</span></to>
</replace>
<replace>
<from>></from>
<to><span class="entity">&gt;</span></to>
</replace>
...
</xsl:variable>
<xsl:variable name="replacements"
select="saxon:node-set($replacements-rtf)/replace" />
<!--
or select="msxsl:node-set($replacements-rtf)/replace" />
...etc for other XSLT Processors' node-set extension functions...
or select="document('')/*/xsl:variable[@name =
'replacements-rtf']/replace" />
-->
then have a template that performs substitution based on this set of
replacements:
<xsl:template name="substitute">
<xsl:param name="string" />
<xsl:variable name="sub"
select="$replacements[contains($string, from)][1]" />
<xsl:choose>
<xsl:when test="$sub">
<xsl:variable name="before"
select="substring-before($string, $sub/from)" />
<xsl:variable name="after"
select="substring-after($string, $sub/from)" />
<xsl:if test="$before">
<xsl:call-template name="substitute">
<xsl:with-param name="string" select="$before" />
</xsl:call-template>
</xsl:if>
<xsl:copy-of select="$sub/to" />
<xsl:if test="$after">
<xsl:call-template name="substitute">
<xsl:with-param name="string" select="$after" />
</xsl:call-template>
</xsl:if>
</xsl:when>
<xsl:otherwise><xsl:value-of select="$string" /></xsl:otherwise>
</xsl:choose>
</xsl:template>
which is then called from a template that matches any text that is
found:
<xsl:template match="text()">
<xsl:call-template name="substitute">
<xsl:with-param name="string" select="." />
</xsl:call-template>
</xsl:template>
Now, this has disadvantages: each bit of the string gets examined
multiple times - the more replacements you have the worse it gets -
but if having to make a replacement is fairly rare, then the higher
reliance of XPath functions might mean it's better for you?
> It wouldn't be necessary to use this unpleasant and inefficient
> technique if XPath defined in its data model, and XSLT supported, a
> char node-type. (Isolating a single character would also allow us to
> access its character value via the number function, which would be
> handy for processing classes of Unicode characters.)
XPointer has something like this with its string ranges. For example,
in XPointer I could do:
string-range(text(), '<')
to get a number of string ranges representing all instances of the
character '<' within the text()'s value. You could imagine a future
version of XSLT incorporating XPointer and having a function to
perform substitution on a set of string ranges.
Sorry I can't be more help,
Jeni
---
Jeni Tennison
http://www.jenitennison.com/
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list