[xsl] Re: Re: AW: AW: global variable and position() once more

Subject: [xsl] Re: Re: AW: AW: global variable and position() once more
From: "Dimitre Novatchev" <dnovatchev@xxxxxxxxx>
Date: Tue, 2 Sep 2003 22:20:50 +0200
Hi Lizet,

The reason for all problems with this source.xml is its very insufficient
structure.

Therefore, it makes sense to apply a two-step solution, the first step of
which produces a new xml document (actually an RTF, which is converted to a
document using the ext:node-set() extension function).

This new document contains all nodes between two "hr" elements as children
of a "section" element.

The second pass applies the previous solution and produces the final result.
The xsl:key instructions are re-defined to match only text nodes that are
children of a "section" with @name having value of "Claims".

The complete code now is:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
 xmlns:ext="http://exslt.org/common";
  exclude-result-prefixes="ext">

 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="kSection"
  match="node()[not(self::hr)]"
  use="generate-id(preceding-sibling::hr[1])"/>

 <xsl:key name="kStart"
  match="section[@name='Claims']/text()
                [preceding-sibling::*[1][self::br]]"
  use="contains(., '.')
     and
       number(substring-before(., '.'))
      =
       number(substring-before(., '.'))"/>

  <xsl:key name="kTrail"
  match="section[@name='Claims']/text()
                [preceding-sibling::*[1][self::br]]"
   use="generate-id(
            preceding-sibling::text()
            [
             contains(., '.')
           and
             number(substring-before(., '.'))
            =
             number(substring-before(., '.'))
            ]
            [1]
                   )"/>

  <xsl:template match="/">
     <xsl:variable name="vrtfStructured">
      <xsl:for-each select="*/hr">
        <section name="{normalize-space(following-sibling::node()[1])}">
         <xsl:copy-of select="key('kSection', generate-id())"/>
        </section>
      </xsl:for-each>
     </xsl:variable>

     <xsl:variable name="vStructured"
select="ext:node-set($vrtfStructured)"/>

     <xsl:for-each select="$vStructured">
      <xsl:for-each select="key('kStart', 'true')">
       <Claim>
        <xsl:copy-of select="normalize-space()"/>
        <xsl:variable name="vLastNumbered" select="position() = last()"/>
        <xsl:for-each select="key('kTrail', generate-id())">
          <xsl:if test="$vLastNumbered or not(position() = last())">
            <xsl:copy-of
             select="concat(substring(.,1,1),
                            normalize-space(substring(.,2))
                            )"/>
          </xsl:if>
        </xsl:for-each>
       </Claim>
      </xsl:for-each>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>


When applied on your source.xml:

<html>
  <hr/>   Claims
  <br/>
  <br/>   I claim:
  <br/>
  <br/>   1. blah blah
  <br/>
  <br/>   more blah blah
  <br/>
  <br/>   2. blah blah blah
  <br/>
  <br/>   more blah blah
  <br/>
  <br/>   3. blah blah
  <br/>
  <br/>   more blah blah
  <br/>
  <br/>   4. blah blah blah
  <br/>
  <br/>   more blah blah
  <br/>
  <hr/>   Description
  <br/>   This is the introduction to the description
  <br/>   1. blah blah
  <br/>
  <br/>   more blah blah
  <br/>
  <br/>   2. blah blah blah

</html>

the wanted result is produced:

<Claim>1. blah blah more blah blah</Claim>
<Claim>2. blah blah blah more blah blah</Claim>
<Claim>3. blah blah more blah blah</Claim>
<Claim>4. blah blah blah more blah blah</Claim>


=====
Cheers,

Dimitre Novatchev.
http://fxsl.sourceforge.net/ -- the home of FXSL

<fe.sola@xxxxxxxxxxxxxx> wrote in message
news:1062521638.3f54cb269eb21@xxxxxxxxxxxxxxxxx
> Hello Dimitre and all,
> The algorithm works very well except for what I mentioned in the previous
email and it
> was definetely my fault. I have contiguous text nodes with the description
that have the
> same list structure, so the xhtml looks like this:
>
> <html>
>   <hr/>   Claims
>   <br/>
>   <br/>   I claim:
>   <br/>
>   <br/>   1. blah blah
>   <br/>
>   <br/>   more blah blah
>   <br/>
>   <br/>   2. blah blah blah
>   <br/>
>   <br/>   more blah blah
>   <br/>
>   <br/>   3. blah blah
>   <br/>
>   <br/>   more blah blah
>   <br/>
>   <br/>   4. blah blah blah
>   <br/>
>   <hr/>   Description
>   <br/>   This is the introduction to the description
>   <br/>   1. blah blah
>   <br/>
>   <br/>   more blah blah
>   <br/>
>   <br/>   2. blah blah blah
>
> </html>
>
> So far what I have on the xslt is:
> <xsl:key name="kStart"
>                      match="text()[preceding-sibling::*[1][self::br]]"
>                      use="contains(., '.')
>                      and
>                      number(substring-before(., '.'))
>                      =
>                      number(substring-before(., '.'))"/>
>
>     <xsl:key name="kTrail"
>                   match="text()[preceding-sibling::*[1][self::br]]"
>                   use="generate-id(
>                             preceding-sibling::text()
>                             [
>                               contains(., '.')
>                               and
>                               number(substring-before(., '.'))
>                               =
>                               number(substring-before(., '.'))
>                            ]
>                            [1]
>                    )"/>
> <xsl:template match="/html/body">
>   <xsl:element name="Claims">
>                <xsl:apply-templates
select="node()[preceding-sibling::text()[starts-with
> (normalize-space(.), 'Claims')] and
following::text()[starts-with(normalize-space
> (.), 'Description')]] " mode="claims"/>
>   </xsl:element>
> </xsl:template>
>
> <xsl:template
match="node()[preceding-sibling::text()[starts-with(normalize-space
> (.), 'Claims')] and following::text()[starts-with(normalize-space(.),
'Description')]] "
> mode="claims">
>                    <xsl:for-each select="key('kStart', 'true')">
>                            <Claim>
>                               <xsl:copy-of select="normalize-space()"/>
>                               <xsl:variable name="vLastNumbered"
select="position() =
> last()"/>
>                            <xsl:for-each select="key('kTrail',
generate-id())">
>
>                                <xsl:if test="$vLastNumbered or
not(position() = last
> ())">
>
>                                      <xsl:copy-of
select="concat(substring(.,1,1),
> normalize-space(substring(.,2)))"/>
>
>                                </xsl:if>
>                             </xsl:for-each>
>                           </Claim>
>                  </xsl:for-each>
> </xsl:template>
>
>
> But in the xml output I'm getting the claims alraight except that in the
last claim I
> get the fisrt text node of the description included and then starts the
description
> list. I know it has to do with:
> node()[preceding-sibling::text()[starts-with(normalize-space(.),
'Claims')] and
> following::text()[starts-with(normalize-space(.), 'Description')]]
> I thought this expression would select the text nodes between 'Claims' and
'Description'
> only so I'm still puzzled why it selects nodes after the 'Description'
text node...
> Thanks a lot for looking at this,
> Lizet
>
> Mensaje citado por Dimitre Novatchev <dnovatchev@xxxxxxxxx>:
>
>
> >
> > Here's the corrected code (the key definitions are omitted as they are
the
> > same:
> >
> > <xsl:stylesheet version="1.0"
> >  xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
> >
> >  <xsl:output omit-xml-declaration="yes" indent="yes"/>
> >  <xsl:strip-space elements="*"/>
> >
> >  <xsl:key name="kStart"
> >   match="text()[preceding-sibling::*[1][self::br]]"
> >   use="contains(., '.')
> >      and
> >        number(substring-before(., '.'))
> >       =
> >        number(substring-before(., '.'))"/>
> >
> >   <xsl:key name="kTrail"
> >   match="text()[preceding-sibling::*[1][self::br]]"
> >    use="generate-id(
> >             preceding-sibling::text()
> >             [
> >              contains(., '.')
> >            and
> >              number(substring-before(., '.'))
> >             =
> >              number(substring-before(., '.'))
> >             ]
> >             [1]
> >                    )"/>
> >
> >   <xsl:template match="/">
> >     <xsl:for-each select="key('kStart', 'true')">
> >      <Claim>
> >       <xsl:copy-of select="normalize-space()"/>
> >       <xsl:variable name="vLastNumbered" select="position() = last()"/>
> >       <xsl:for-each select="key('kTrail', generate-id())">
> >         <xsl:if test="$vLastNumbered or not(position() = last())">
> >           <xsl:copy-of
> >            select="concat(substring(.,1,1),
> >                           normalize-space(substring(.,2))
> >                           )"/>
> >         </xsl:if>
> >       </xsl:for-each>
> >      </Claim>
> >     </xsl:for-each>
> >   </xsl:template>
> > </xsl:stylesheet>
> >
> > I believe that two very good books on XSLT are the following:
> >
> >   "Beginning XSLT" by Jeni Tennison
> >
> >   "XSLT Programmer's Reference" by Michael Kay.
> >
> >
> >
> >
> >
> >
> >
> >
> >
> > =====
> > Cheers,
> >
> > Dimitre Novatchev.
> > http://fxsl.sourceforge.net/ -- the home of FXSL
> >
> > __________________________________
> > Do you Yahoo!?
> > Yahoo! SiteBuilder - Free, easy-to-use web site design software
> > http://sitebuilder.yahoo.com
> >
> >  XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
> >
>
>
>
>
> -------------------------------------------------
> Este mensaje fue enviado usando el servicio de correo en web de Infomed
> http://webmail.sld.cu
>
>  XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
>
>




 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread