[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

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


Subject: Re: [xsl] variable outside a for-each loop: second try
From: Abel Braaksma <abel.online@xxxxxxxxx>
Date: Thu, 20 Sep 2007 23:03:23 +0200

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.


Cheers,
-- Abel Braaksma


Current Thread
Keywords