This is the mail archive of the
xsl-list@mulberrytech.com
mailing list .
Re: Truncating output of a node
- To: Jim Schmidt <JSchmidt at yet2 dot com>
- Subject: Re: [xsl] Truncating output of a node
- From: Jeni Tennison <mail at jenitennison dot com>
- Date: Thu, 19 Apr 2001 23:17:40 +0100
- CC: "'xsl-list at lists dot mulberrytech dot com'" <xsl-list at lists dot mulberrytech dot com>
- Organization: Jeni Tennison Consulting Ltd
- References: <D090FE9586C9D4119E4E00A02493157A05C5F7@ferris.tahoe.yet2.com>
- Reply-To: xsl-list at lists dot mulberrytech dot com
Hi Jim,
> I guess another possibility it to output n characters and add '...'
> at the end to create the summary. Is that any easier?
I can just tell everyone's dying for a patented Jeni solution to this
problem. So here's my approach - step through the nodes one by one,
keeping track of the number of sentences that have been output so far
(as Mike suggested). Be careful, though - text nodes might hold more
than one sentence, so you need to have some recursion over the string
in there as well.
So have one template for text nodes:
<xsl:template match="text()" name="text">
<!-- $sentences holds the number of sentences covered so far -->
<xsl:param name="sentences" select="0" />
<!-- $text holds the text of the text node (or portion of a text
node when this template is called recursively -->
<xsl:param name="text" select="." />
<!-- $next holds the next node to move on to -->
<xsl:param name="next" select="following-sibling::*[1]" />
<xsl:choose>
<!-- if this text contains a sentence delimiter... -->
<xsl:when test="contains($text, '. ')">
<!-- ... finish the sentence ... -->
<xsl:value-of select="substring-before($text, '. ')" />
<xsl:text>. </xsl:text>
<!-- ... and if we've output less than 2 sentences before
(i.e. we've not just finished the third) ... -->
<xsl:if test="$sentences < 2">
<!-- ... call the template on the rest of the string ...
-->
<xsl:call-template name="text">
<!-- ... adding one to the sentences count -->
<xsl:with-param name="sentences" select="$sentences + 1" />
<!-- ... passing the rest of the text node -->
<xsl:with-param name="text"
select="substring-after($text, '. ')" />
<!-- ... and keeping the same next node -->
<xsl:with-param name="next" select="$next" />
</xsl:call-template>
</xsl:if>
</xsl:when>
<xsl:otherwise>
<!-- ... otherwise just give the value of the string ... -->
<xsl:value-of select="$text" />
<!-- ... and apply templates to the following span element,
keeping the number of sentences the same -->
<xsl:apply-templates select="$next">
<xsl:with-param name="sentences" select="$sentences" />
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Have another template for span elements, which can be a lot simpler,
just basically applies templates to the next node, passing through the
same count - this takes advantage of the fact that sentences never end
within span elements:
<xsl:template match="span">
<xsl:param name="sentences" select="0" />
<xsl:copy-of select="." />
<xsl:apply-templates select="following-sibling::node()[1]">
<xsl:with-param name="sentences" select="$sentences" />
</xsl:apply-templates>
</xsl:template>
Then you can start the process by just applying templates to the first
node under the summary:
<xsl:template match="summary">
<xsl:apply-templates select="node()[1]" />
</xsl:template>
I hope that helps,
Jeni
---
Jeni Tennison
http://www.jenitennison.com/
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list