This is the mail archive of the xsl-list@mulberrytech.com mailing list .


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Counting number of characters of sibling text node


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]