This is the mail archive of the
xsl-list@mulberrytech.com
mailing list .
Re: String parsing in XSLT/XPath?
- To: Ying Qin <yqin at portal dot com>
- Subject: Re: [xsl] String parsing in XSLT/XPath?
- From: Jeni Tennison <mail at jenitennison dot com>
- Date: Sat, 8 Sep 2001 11:50:33 +0100
- CC: "'xsl-list at lists dot mulberrytech dot com'" <xsl-list at lists dot mulberrytech dot com>
- Organization: Jeni Tennison Consulting Ltd
- References: <C47CCC6238EFD4119C5200508B95A1006E9A55@cup1ex1.portal.com>
- Reply-To: xsl-list at lists dot mulberrytech dot com
Hi Ying,
> I need to transform an XML doc to an HTML doc. There is one element
> that contains multiple lines and will need to be shown in the HTML
> doc as multiple lines as well. Bascially I will need to put <BR/> to
> the end of each line of that element.
You need to use a recursive template to search and replace within the
string. Here is one:
<xsl:template match="node()" mode="replaceLineBreaks"
name="replaceLineBreaks">
<xsl:param name="string" select="." />
<xsl:choose>
<!-- if the string contains a line break... -->
<xsl:when test="contains($string, '
')">
<!-- give the part before the line break... -->
<xsl:value-of select="substring-before($string, '
')" />
<!-- then a br element... -->
<br />
<!-- and then call the template recursively on the rest of the
string -->
<xsl:call-template name="replaceLineBreaks">
<xsl:with-param name="string"
select="substring-after($string, '
')" />
</xsl:call-template>
</xsl:when>
<!-- if the string doesn't contain a line break, just give its
value, followed by a br element -->
<xsl:otherwise>
<xsl:value-of select="$string" /><br />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
You can apply this template to the ADDRESS element with:
<xsl:apply-templates select="ADDRESS" mode="replaceLineBreaks" />
I doubt this is relevant, since you're dealing with addresses, which
tend to be fairly short, but if you're dealing with long strings with
lots of line breaks in them, then you may find it more efficient to
use a divide-and-conquer approach whereby you split the remaining
string. This has the advantage of limiting the depth of the recursion,
and therefore the call stack, but the disadvantage of not being tail
recursive and therefore not amenable to optimisation:
<xsl:template match="node()" mode="replaceLineBreaks"
name="replaceLineBreaks">
<xsl:param name="string" select="." />
<xsl:choose>
<!-- if the string contains a line break... -->
<xsl:when test="contains($string, '
')">
<!-- give the part before the line break... -->
<xsl:value-of select="substring-before($string, '
')" />
<!-- then a br element... -->
<br />
<!-- and then call the template recursively on the rest of the
string, splitting it into two to limit the depth of the
recursion -->
<xsl:variable name="remainingString"
select="substring-after($string, '
')" />
<xsl:variable name="halfRemainingStringLength"
select="floor(string-length($remainingString) div 2)" />
<xsl:call-template name="replaceLineBreaks">
<xsl:with-param name="string"
select="substring($remainingString, 1,
$halfRemainingStringLength)" />
</xsl:call-template>
<xsl:call-template name="replaceLineBreaks">
<xsl:with-param name="string"
select="substring($remainingString,
$halfRemainingStringLength + 1)" />
</xsl:call-template>
</xsl:when>
<!-- if the string doesn't contain a line break, just give its
value -->
<xsl:otherwise>
<xsl:value-of select="$string" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
With this, you will have to add the <br /> to the end of the string
yourself.
If performance is an issue, I suggest that you try both of the
templates on your particular data and processor to see which is best
for you; if neither is significantly faster than the other, then use
the one you feel most comfortable with maintaining.
I hope that helps,
Jeni
---
Jeni Tennison
http://www.jenitennison.com/
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list