After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 607893 - Problem with <xsl:key />
Problem with <xsl:key />
Status: RESOLVED FIXED
Product: libxslt
Classification: Platform
Component: general
1.1.26
Other All
: Normal blocker
: ---
Assigned To: Daniel Veillard
libxml QA maintainers
Depends on:
Blocks:
 
 
Reported: 2010-01-23 21:01 UTC by whaefelinger
Modified: 2013-12-13 21:11 UTC
See Also:
GNOME target: ---
GNOME version: ---



Description whaefelinger 2010-01-23 21:01:10 UTC
I'm trying to cross-reference elements and found a problem. Here's the very short XML data:
<test>
  <h level="1" />      <!-- id1 -->        
  <h level="2" />      <!-- id2 -->
  <h level="2" />      <!-- id3 -->
  <h level="1" />      <!-- id4 -->
  <h level="2" />      <!-- id5 -->
</test>
For each <h />, I want to calculate the <h />'s that follow and have a level higher than the current one. The search should stop with the next following <h /> which has a higher level.

This is the expression to be evaluated on each <h /> node:

  (preceding::h[ @level &lt; current()/@level ])[last()]

Let's do it manually first (I identify each node by it's id: so id3 is the third node in the above document, i.e. <h level="2" />)
+------+--------------+
| Node | node-set     |
+------+--------------+
| id1  |  {}          |
+------+--------------+
| id2  |  {id1}       |
+------+--------------+
| id3  |  {id1}       |
+------+--------------+
| id4  |  {}          |
+------+--------------+
| id5  |  {id4}       |
+------+--------------+

This is my stylesheet:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>

  <xsl:key name="F"
           match="h"
           use=" generate-id(  (preceding::h[ @level &lt; current()/@level ]) [last()]   )"/>

  <!-- start -->
  <xsl:template match="/*">
    <dump>
      <xsl:for-each select="//h" >
        <xsl:variable name="hid" select="generate-id(.)" />
        <xsl:value-of select=" concat($hid,' : {')" />
        <xsl:for-each select="  key('F',$hid) " >
          <xsl:value-of select="concat(' ',generate-id(.))" />
        </xsl:for-each>
        <xsl:value-of select=" '}&#10;' " />
      </xsl:for-each>
    </dump>
  </xsl:template>
 </xsl:stylesheet>

Here is the output when using Saxon-HE (9.x):

<dump>
 d1e5  : { d1e11 d1e16}
 d1e11 : {}
 d1e16 : {}
 d1e20 : { d1e24}
 d1e24 : {}
</dump>

That's correct according to table calculated manually above.

Next, xsltproc --version:
Using libxml 20706, libxslt 10126 and libexslt 815
xsltproc was compiled against libxml 20706, libxslt 10126 and libexslt 815
libxslt 10126 was compiled against libxml 20706
libexslt 815 was compiled against libxml 20706

Then the output:

<dump>
id70347 : {}
id70357 : {}
id70365 : {}
id70374 : {}
id70383 : {}
</dump>

Eh, sorry, *not* correct.

I have no clue what went on. I am suspiciuous though, that it has something to do with function current(). According to my understanding, current() should change the meaning. Usually, current() and '.' are the same. When using in predicate above, current() should indeed become the node on which the expr is being evaluated. On the other hand, if you simply calculate the above expr outside of <xsl:key />, as here shown

<xsl:for-each select="//h" >
  <xsl:value-of select=" preceding::h[@level &lt; current()/@level] " />
</xsl:for-each>

then everything - especially current() - works fine.
Comment 2 whaefelinger 2013-12-13 21:11:39 UTC
I'm glad to notice that this bug got fixed, especially since the popularity of this problem was rather low :-)