|
|
|
date: Wed, 06 Feb 2008 19:47:46 +0100,
group: microsoft.public.xsl
back
Implementing a "State Machine" in XSL?
Hello,
i need to use XSL to truncate a HTML fragment, keeping the tags intact.
So for example, i want to truncate this HTML to include ~15 visible
characters:
<b>This is a <span style="color: #888">very long</span> Text</b>
The result should be:
<b>This is a <span style="color: #888">very </span></b>
As you see, i ignore the tags and count to 15. But then i may have open
tags, so i close the open tags (which means i somehow need to keep track
of which tags are still open).
In conventional programming, i would use a state machine for this, but I
do not know enough about XSLT to do that.
Any hints?
--
http://www.Stum.de · http://www.Souvenance.net
e-Mail Adresse ist gültig, wird aber äußerst selten gelesen.
e-Mail address is valid, but read very infrequently.
date: Wed, 06 Feb 2008 19:47:46 +0100
author: Michael Stum
Re: Implementing a "State Machine" in XSL?
That's trivial in XSLT 2.0 and a bit cumbersome in pure XSLT 1.0.
One idea is to traverse the tree in document order and checking if
current element would exceed max length. If it would not then output it
and move to the next one. If it would, process this node children
recursively. If you come down to a text node that's too long, split it.
Here is a sketch implementation. It's far from perfect, but you get the
idea.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="max-len" select="15"/>
<xsl:template match="/">
<xsl:call-template name="output">
<xsl:with-param name="nodes" select="*"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="output">
<xsl:param name="running-length" select="0"/>
<xsl:param name="nodes" select="/.."/>
<xsl:choose>
<xsl:when test="string-length($nodes[1]) + $running-length <=
$max-len">
<xsl:copy-of select="$nodes[1]"/>
<xsl:if test="$nodes[2]">
<xsl:call-template name="output">
<xsl:with-param name="running-length"
select="string-length($nodes[1]) + $running-length"/>
<xsl:with-param name="nodes" select="$nodes[position() !=
1]|$nodes[1]/*"/>
</xsl:call-template>
</xsl:if>
</xsl:when>
<xsl:when test="$nodes[1]/self::text()">
<xsl:value-of select="substring($nodes[1], 1, $max-len -
$running-length)"/>
</xsl:when>
<xsl:otherwise>
<xsl:if test="$nodes[1]/node()">
<xsl:element name="{name($nodes[1])}"
namespace="{namespace-uri($nodes[1])}">
<xsl:copy-of select="$nodes[1]/@*"/>
<xsl:call-template name="output">
<xsl:with-param name="running-length"
select="$running-length"/>
<xsl:with-param name="nodes" select="$nodes[1]/node()"/>
</xsl:call-template>
</xsl:element>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
--
Oleg
Michael Stum wrote:
> Hello,
>
> i need to use XSL to truncate a HTML fragment, keeping the tags intact.
> So for example, i want to truncate this HTML to include ~15 visible
> characters:
>
> <b>This is a <span style="color: #888">very long</span> Text</b>
>
> The result should be:
> <b>This is a <span style="color: #888">very </span></b>
>
> As you see, i ignore the tags and count to 15. But then i may have open
> tags, so i close the open tags (which means i somehow need to keep track
> of which tags are still open).
>
> In conventional programming, i would use a state machine for this, but I
> do not know enough about XSLT to do that.
>
> Any hints?
>
date: Thu, 07 Feb 2008 13:11:56 +0200
author: Oleg Tkachenko
|
|