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 530871 - xsl:key, sibling axes
xsl:key, sibling axes
Status: RESOLVED FIXED
Product: libxslt
Classification: Platform
Component: general
1.1.22
Other All
: Normal normal
: ---
Assigned To: Daniel Veillard
libxml QA maintainers
Depends on:
Blocks:
 
 
Reported: 2008-05-01 11:10 UTC by Michael Ludwig
Modified: 2013-12-13 17:06 UTC
See Also:
GNOME target: ---
GNOME version: ---



Description Michael Ludwig 2008-05-01 11:10:47 UTC
Please describe the problem:
This is a slighty modified version of a post to the Gnome XSLT library mailing list <XSLT@GNOME.org>. See:

http://mail.gnome.org/archives/xslt/2008-April/msg00027.html

The xsl:key does not seem to always work correctly in LibXSLT when its @use attribute involves any, or both, of the sibling axes.

I happened to code something LibXSLT interprets differently
than its fellow processors Saxon 6.5.5 and 9.0.0.2 (Java), Xalan-C
1.10.0 and Sablotron 1.0.3.

All this occurs on Linux Ubuntu, both using the distribution package
1.1.20-0ubuntu2 (version 10120, according to xsltproc -V) and compiling
from source (version 1.1.22, all tests passed, including key tests,
using newest available LibXML2, version 2.6.31).

$ /usr/local/bin/xsltproc -V
Using libxml 20631, libxslt 10122 and libexslt 813
xsltproc was compiled against libxml 20631, libxslt 10122 and libexslt 813
libxslt 10122 was compiled against libxml 20631
libexslt 813 was compiled against libxml 20631

Steps to reproduce:
The problem can be reproduced by using xsltproc to transform the supplied data using the supplied XSLT program.

Here's my data. There are a number of ChGr elements identified by @ID
and representing groups of TV channels. Some of those also have a @name.
I call these super-groups and use them to refer to several related
groups. What's related is implicitly defined by document order: The
super-group a given ChGr belongs to is either its own @name or, in the
case of its absence, the first preceding ChGr/@name in axis order.

So we have (1,2,3), (4,5), (6,7,8), (9), (10,11) and (12).

<ChannelGroups>
   <ChGr ID="1" name="Hauptsender"/><!-- super-group -->
   <ChGr ID="2"/><!-- part II of this super-group -->
   <ChGr ID="3"/><!-- part III -->
   <ChGr ID="4" name="Regionalsender"/><!-- new super-group -->
   <ChGr ID="5"/><!-- part II, and so on; super-group is: -->
   <ChGr ID="6" name="Lokalsender"/><!-- on self axis -->
   <ChGr ID="7"/><!-- on preceding-sibling axis -->
   <ChGr ID="8"/><!-- and so on -->
   <ChGr ID="9" name="Spartensender"/>
   <ChGr ID="10" name="Infosender"/>
   <ChGr ID="11"/>
   <ChGr ID="12" name="Sportsender"/>
</ChannelGroups>

For easy access, I define a key that returns the super-group ChGr
element node for any given ChGr/@ID.

<xsl:transform version="1.0"
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="text"/>
   <xsl:key name="super-group" match="ChGr[@name]"
     use=" @ID |
     following-sibling::ChGr[ not(@name) ][
       preceding-sibling::ChGr[ @name ][ 1 ]/@ID = current()/@ID
     ]/@ID"/>
   <xsl:template match="ChannelGroups">
     <xsl:value-of select="system-property('xsl:vendor')"/>
     <xsl:text>&#10;</xsl:text>
     <xsl:for-each select="ChGr">
       <xsl:variable name="sg" select="key('super-group', @ID)/@ID"/>
       <xsl:value-of select="@ID"/>
       <xsl:text> </xsl:text>
       <xsl:value-of select="$sg"/>
       <xsl:if test="@ID = $sg"> *super*</xsl:if>
       <xsl:text>&#10;</xsl:text>
     </xsl:for-each>
   </xsl:template>
</xsl:transform>

Actual results:
Here's the output.

     Saxon & Co          LibXSLT
     ----------          -------
     1 1 *super*         1 1 *super*
     2 1                 2
     3 1                 3
     4 4 *super*         4 4 *super*
     5 4                 5
     6 6 *super*         6 6 *super*
     7 6                 7
     8 6                 8
     9 9 *super*         9 9 *super*
     10 10 *super*       10 10 *super*
     11 10               11
     12 12 *super*       12 12 *super*

The key() lookups seem to fail where the super-group node is to be found
on the preceding-sibling axis.

I suspect this is a bug in LibXSLT. Is it?

Expected results:
I would expect the output of LibXSLT to be the same as the output of its fellow processors.

Does this happen every time?
The erroneous output happens every time.

Other information:
Comment 1 Daniel Veillard 2008-05-13 14:53:47 UTC
Possibly a libxml2 XPath evaluation bug, but my head spins
just looking at the example. Any way you could reduce the
XSL and XML data to just expose the problem ?
looking at xltproc -v output may help spot what is the
actual problem,

 thanks,

Daniel
Comment 2 Michael Ludwig 2008-05-13 23:12:32 UTC
Daniel, thanks for looking into this. You're right, the example is too confusing. (First bug report I've ever made.) Trying to reduce the complexity has actually exposed the bug. It does *not*, as claimed in the title I've given to this bug entry, pertain to the sibling axes. Instead, it has to do with the XSLT 1.0 current() function. I hope the following example will be clearer to you.

$ cat libxslt-key-current.xml
<Root>
   <Elm ID="1" name="a"/>
   <Elm ID="2"/>
   <Elm ID="3"/>
   <Elm ID="4" name="b"/>
   <Elm ID="5"/>
   <Elm ID="6" name="c"/>
</Root>

$ cat libxslt-key-current-simple.xsl
<xsl:transform version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text"/>

  <!-- a parameter to let you choose the key by name -->
  <xsl:param name="k" select="'k1'"/>

  <!-- A non-sensical key, to demonstrate the problem. -->
  <xsl:key name="k1" match="Elm[@name]" use="          @ID"/>
  <xsl:key name="k2" match="Elm[@name]" use="current()/@ID"/>
  <!-- And an equivalent key, which does not work. -->

  <xsl:template match="*">
    <xsl:apply-templates select="*"/>
  </xsl:template>

  <xsl:template match="Elm">
    <xsl:value-of select="@ID"/>
    <xsl:for-each select="key($k, @ID)/@name">
      <xsl:text> </xsl:text><xsl:value-of select="."/>
    </xsl:for-each>
    <xsl:text>&#10;</xsl:text>
  </xsl:template>
</xsl:transform>

$ xsltproc libxslt-key-current-simple.xsl libxslt-key-current.xml 
1 a
2
3
4 b
5
6 c

$ xsltproc --stringparam k k2 libxslt-key-current-simple.xsl libxslt-key-current.xml 
1
2
3
4
5
6

In both cases, the output should be as in the first case ("k1").

The spec says:

  "The current function returns a node-set
  that has the current node as its only member."
  -- http://www.w3.org/TR/xslt#function-current

The spec does not say that during key creation, there is no current node. It says:

  "[...] a node x has a key with name y and
  value z if and only if there is an xsl:key
  element such that: [...] when the expression
  specified in the use attribute of the xsl:key
  element is evaluated with x as the current
  node and with a node list containing just x
  as the current node list [...]"
  -- http://www.w3.org/TR/xslt#element-key

I hope this helps to clarify the issue.

Thanks once more for taking care of this bug!

Michael Ludwig
Comment 4 Michael Ludwig 2013-12-13 17:06:18 UTC
Danke … nach fünfeinhalb Jahren gefixt!!! :)

I git-got your commit, compiled and tested, all good now! Thanks!