Re: [xsl] variable outside a for-each loop: second try

Subject: Re: [xsl] variable outside a for-each loop: second try
From: "Mathieu Malaterre" <mathieu.malaterre@xxxxxxxxx>
Date: Fri, 21 Sep 2007 15:29:54 +0200
On 9/20/07, Abel Braaksma <abel.online@xxxxxxxxx> wrote:
> Mathieu Malaterre wrote:
> > $  java -jar /usr/share/Dart/Source/Server/saxon/saxon8.jar  -t
> > Saxon 8.0 from Saxonica
> > Java version 1.6.0_01
> > No source file name
> >
>
> ouch, that must be at least three years old! High time to upgrade to 8.9
> at the very least! So much has changed since then.
>
> >     <xsl:for-each select="//informaltable">
> >
>
> someone already told you this on this thread, but really, try to refrain
> from //. It is very costly and will cause you more harm (walking the
> full tree of all nodes to find whether they match 'informaltable') than
> good. Just use the path as it is, in your case: select="informaltable".
>
> > When I tried your solution here is what I get:.
> >
> >     <entry ie="{(entry[1]/para[. != ''] |
> > preceding-sibling::row[entry[1]/para != ''][1])[1]}"
> > module="{entry[2]/para}" reference="{entry[3]/para}"
> > usage="{entry[4]/para}"/>
> >   </xsl:template>
> >
>
> My solution was meant as a hint, not as a full solution. But my
> apologies for leaving such an obvious bug into the stylesheet; that
> happens when you only type them in the mail and don't try them before
> sending. There are two bugs:
>
>   1. The obvious one: the prec-sibl statement requests for the element
> "row", not for the element "para", which is what you were after.
>   2. The less obvious is the one of document order: the last [1] will
> select the *first* to appear in document order of the two elements
> specified between the parentheses before it. That means: the prec-sibl
> row will always be chosen. Change it to use the , (comma) operator or
> change [1] to [last()].
>
> After these fixes the @ie-statement becomes:
>
> {(entry[1]/para[. != ''] , preceding-sibling::row/entry[1]/para[. !=
> ''][1])[1]}
>
>
> >
> > Gives:
> >
> > <?xml version="1.0" encoding="UTF-8"?>
> > <entry ie="Col1 A" module="Col2 A" reference="" usage=""/>
> > <entry ie="&#xA;   &#xA;     Col1 A&#xA;   &#xA;   &#xA;     Col2
> > A&#xA;   &#xA; " module="Col2 B" reference="" usage=""/>
> > <entry ie="&#xA;   &#xA;     Col1 A&#xA;   &#xA;   &#xA;     Col2
> > A&#xA;   &#xA; " module="Col2 C" reference="" usage=""/>
> > <entry ie="&#xA;   &#xA;     Col1 A&#xA;   &#xA;   &#xA;     Col2
> > A&#xA;   &#xA; " module="Col2 D" reference="" usage=""/>
> >
>
> Weird behavior like this is what happens when you use a very out of date
> processor that is implemented on a very old draft version of a now
> completely finalized (and in quite some areas changed) specification.
> The whitespace that you see is caused by the preceding-sibling::row
> elements, which contain non-significant whitespace. With a correctly
> behaving processor, this whitespace would normally be ignored (note that
> &#xA; is also whitespace! It is the newline that is between <row> and
> <entry> and between <entry> and <para> etc).
>
> The output with my original stylesheet, just as you put it above, is as
> follows with a normal recent version of any XSLT 2.0 processor:
>
> <?xml version="1.0" encoding="UTF-8"?>
> <table>
>    <entry ie="Col1 A" module="Col2 A" reference="" usage=""/>
>    <entry ie="Col1 ACol2 A" module="Col2 B" reference="" usage=""/>
>    <entry ie="Col1 ACol2 A" module="Col2 C" reference="" usage=""/>
>    <entry ie="Col1 ACol2 A" module="Col2 D" reference="" usage=""/>
> </table>
>
> Which is not correct, of course, but vastly different from your output.
> By now I hope you are convinced to upgrade your processor ;) it will
> save you (and us) gazillions of time.
>
> This is the XSLT I used to test my bug fixes (but still: it is not more
> than a hint, I am sure you want to tweak it further). Note the comma
> operator and the absence of //:
>
>     <xsl:template match="/">
>         <xsl:apply-templates select="*" />
>     </xsl:template>
>
>     <xsl:template match="informaltable">
>         <table>
>             <xsl:apply-templates />
>         </table>
>     </xsl:template>
>
>     <xsl:template match="row">
>         <entry ie="{(entry[1]/para[. != ''] ,
> preceding-sibling::row/entry[1]/para[. != ''][1])[1]}"
>             module="{entry[2]/para}" reference="{entry[3]/para}"
>             usage="{entry[4]/para}"/>
>     </xsl:template>
>
>
> This is the output:
>
> <?xml version="1.0" encoding="UTF-8"?>
> <table>
>    <entry ie="Col1 A" module="Col2 A" reference="" usage=""/>
>    <entry ie="Col1 A" module="Col2 B" reference="" usage=""/>
>    <entry ie="Col1 A" module="Col2 C" reference="" usage=""/>
>    <entry ie="Col1 D" module="Col2 D" reference="" usage=""/>
> </table>
>
>
> Hope this info will help you further.


Thanks,

  This should close the thread. I don't think I was able to describe
my problem correctly using both your solution and the xsl:transform I
am not getting what I called the 'last' preceeding entry.

Docs are here:

 https://gdcm.svn.sourceforge.net/svnroot/gdcm/Sandbox/xslt/

In both case I get something like:


<?xml version="1.0" encoding="UTF-8"?>
<table>
   <entry ie="Col1 A" module="Col2 A" reference="" usage=""/>
   <entry ie="Col1 A" module="Col2 B" reference="" usage=""/>
   <entry ie="Col1 A" module="Col2 C" reference="" usage=""/>
   <entry ie="Col1 D" module="Col2 D" reference="" usage=""/>
   <entry ie="Col1 E" module="Col2 E" reference="" usage=""/>
   <entry ie="Col1 A" module="Col2 F" reference="" usage=""/>
   <entry ie="Col1 A" module="Col2 G" reference="" usage=""/>
</table>

The last two lines contains 'Col1 A' which is not what I called 'last'
preceeding. It should have been:


<?xml version="1.0" encoding="UTF-8"?>
<table>
   <entry ie="Col1 A" module="Col2 A" reference="" usage=""/>
   <entry ie="Col1 A" module="Col2 B" reference="" usage=""/>
   <entry ie="Col1 A" module="Col2 C" reference="" usage=""/>
   <entry ie="Col1 D" module="Col2 D" reference="" usage=""/>
   <entry ie="Col1 E" module="Col2 E" reference="" usage=""/>
   <entry ie="Col1 E" module="Col2 F" reference="" usage=""/>
   <entry ie="Col1 E" module="Col2 G" reference="" usage=""/>
</table>

Thanks again all for your help. I did not meant to be rude. But I felt
like I would ask a very simple question on the C++ newsgroup and
people would tell me to use C++0x .


I have ordered an XSLT book,

-- 
Mathieu

Current Thread