This is the mail archive of the
xsl-list@mulberrytech.com
mailing list .
Re: Counting number of characters of sibling text node
- From: Dimitre Novatchev <dnovatchev at yahoo dot com>
- To: xsl-list at lists dot mulberrytech dot com
- Date: Wed, 22 May 2002 07:01:03 -0700 (PDT)
- Subject: [xsl] Re: Counting number of characters of sibling text node
- Reply-to: xsl-list at lists dot mulberrytech dot com
And here's a functional solution. Just use the scanl() function from
FXSL, passing to it a list of text nodes, an initial value 0 and a
function, which adds to the current result the string-length() of the
current argument.
This will give you all partial sums of string-lengths. If you want the
sum just for one text node, you'll use almost the same solution, but
the FXSL function should be foldl(), not scanl().
stylesheet:
----------
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:addLength="f:addLength"
exclude-result-prefixes="addLength"
>
<xsl:import href="scanl.xsl"/>
<addLength:addLength/>
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="vAddLength"
select="document('')/*/addLength:*[1]"/>
<xsl:call-template name="scanl">
<xsl:with-param name="pFun" select="$vAddLength"/>
<xsl:with-param name="pQ0" select="0"/>
<xsl:with-param name="pList" select="/t/text()"/>
</xsl:call-template>
</xsl:template>
<xsl:template match="addLength:*">
<xsl:param name="pArg1"/>
<xsl:param name="pArg2" select="/.."/>
<xsl:value-of select="$pArg1 + string-length($pArg2)"/>
</xsl:template>
</xsl:stylesheet>
source xml:
----------
<t><br/>a<br/>ab<br/>abc<br/>abcd</t>
Result:
------
<el>0</el>
<el>1</el>
<el>3</el>
<el>6</el>
<el>10</el>
Cheers,
Dimitre Novatchev.
--- Dimitre Novatchev <dnovatchev@yahoo.com> wrote:
> > What I want to do is to count the number os characters in a text
> > node and all previous text nodes children of the current text
> node's
> > parent.
> >
> > parent
> > |
> > ----------------------------
> > | | | |
> > text1 <br/> text2 <br/>
> >
> >
> > When having text1 has the current node my template would return
> the
> > number of characters of text1 but when having text2 has the current
>
> > node my template would return the sum of number of characters of
> > text1 with number of characters of text2.
> >
> > I've tried using the following template:
> >
> > <xsl:template match="text()" mode="getStrLen">
> > <xsl:variable name="pastTxtLen"><xsl:apply-templates
> > select="preceding-sibling::text()[1]"
> > mode="getStrLen"/></xsl:variable>
> > <xsl:value-of select="string-length($pastTxtLen) + string-length
> > (.)" />
> > </xsl:template>
> >
> > I get it's result by doing:
> > <xsl:variable name="pastTxtLen"><xsl:apply-templates select="."
> > mode="getStrLen"/></xsl:variable>
> >
> > Doing it this way I get the rong result.
> > For the example above, when I have text1 has the current node it
> > works fine(the number of characters of text1 only is returned) but
> > when I have text2 has the current node a rong result.
> >
> > Any suggestions?
>
> You're almost there, just two things:
>
> 1. Change
>
> > <xsl:value-of select="string-length($pastTxtLen) + string-length
> > (.)" />
>
> to
>
> <xsl:value-of select="$pastTxtLen + string-length(.)" />
>
>
> 2. In case there are no preceding siblings that are text nodes, the
> value of $pastTxtLen will be the empty nodeset, which is not a
> number.
> As a result you'll get NaN adding to it anything. Therefore, you need
> to process this special case in an appropriate way.
>
> Here's one solution:
>
> stylesheet:
> ----------
> <xsl:stylesheet version="1.0"
> xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
> <xsl:output omit-xml-declaration="yes"/>
>
> <xsl:strip-space elements="*"/>
>
> <xsl:template match="/">
>
> <xsl:for-each select="/t/text()">
> <xsl:apply-templates select="." mode="getStrLen"/>
> <xsl:text>
</xsl:text>
> </xsl:for-each>
> </xsl:template>
> <xsl:template match="text()" mode="getStrLen">
> <xsl:variable name="vPrecText"
> select="preceding-sibling::text()[1]"/>
> <xsl:variable name="pastTxtLen">
> <xsl:choose>
> <xsl:when test="$vPrecText">
> <xsl:apply-templates mode="getStrLen"
> select="$vPrecText[1]" />
> </xsl:when>
> <xsl:otherwise>0</xsl:otherwise>
> </xsl:choose>
> </xsl:variable>
> <xsl:value-of select="$pastTxtLen + string-length(.)" />
> </xsl:template>
> </xsl:stylesheet>
>
> source xml:
> ----------
> <t><br/>a<br/>ab<br/>abc<br/>abcd</t>
>
> Result:
> ------
> 1
> 3
> 6
> 10
>
>
> Cheers,
> Dimitre Novatchev.
>
>
>
>
> __________________________________________________
> Do You Yahoo!?
> LAUNCH - Your Yahoo! Music Experience
> http://launch.yahoo.com
>
__________________________________________________
Do You Yahoo!?
LAUNCH - Your Yahoo! Music Experience
http://launch.yahoo.com
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list