GNOME Bugzilla – Bug 538580
wrong xpath matching on text()[ position-number ]
Last modified: 2013-08-04 23:35:47 UTC
Overview Description: The "text()[2]" expression must matches a node with position 2 within a text-nodes, but now it works like "text()[ count(preceding-sibling::node()) + 1 = 2]". Steps to Reproduce: xsltproc test2.xsl data.xml (test-case will be attached) Actual Results: <body><p>text()[2]: text 1 </p><p>b[2]: b 2 </p></body> Expected Results: <body><p>b[2]: b 2 </p><p>text()[2]: text 2 </p></body> Additional Information: > xsltproc -version Using libxml 20632, libxslt 10123 and libexslt 813 xsltproc was compiled against libxml 20632, libxslt 10123 and libexslt 813 libxslt 10123 was compiled against libxml 20632 libexslt 813 was compiled against libxml 20632
Created attachment 112821 [details] data.xml — source data
Created attachment 112823 [details] test2.xsl — testcase
Created attachment 112824 [details] data.xml — source data
(In reply to comment #0) This does not appear to be a bug. The stylesheet applies templates to the following set of nodes: "/root/body/node()". That is a set of four nodes that consists, in order, of: a 'b' element, a text node, another 'b' element, and another text node. At that point, the context positions are established: position 1) first 'b' element position 2) first text() node position 3) second 'b' element position 4) second text() node These are then evaluated for a template match in order. The first 'b' element has context position (1), so it does not match the pattern "b[2]", which is equivalent to "b[position()=2]". The first text() node DOES match the pattern "text()[2]" because it is a text node, and its position (which was established by the last apply-templates) IS equal to (2). Because "text()[2]" is a top-level expression, the context positions established by the apply-templates are the ones in effect. You could get the effect you presumably were expecting by using a nested expression that establishes the context positions you wanted: <xsl:template match="text()[count(.|(../text()[position()=2]))=1]"> In this case, for each text() node in the node-set being examined, a check is made to see if it's the same node as the 2nd text() node of the parent node. The nested expression ("../text()") creates a new context for position numbering, and this time the context is "all the child text nodes of my parent", which produces the results you indicate you expected.
> The first text() node DOES match the pattern "text()[2]" because it is a text node, and its position (which was established by the last apply-templates) IS equal to (2). 1. In this case why does the second "b" node match the patter "b[2]" while its "position" IS eqeual to (4)? 2. The node-set and proximity position are established by axis and node-test parts of the location step ("initial node-set from the axis and node-test"), see http://www.w3.org/TR/xpath#section-Location-Steps 3. Look on the results by Saxon, msxsl, IE, Firefox — they all return the expected correct results.
* typo: second "b" position IS eqeual to (3) (within nodes by pattern "node()")
I have an additional test case that show this bug. Here is the output of two xslt processors converting t.xml with t.xsl: $ xsltproc t.xsl t.xml <?xml version="1.0"?> <result> <bad text="hello" position="1"/> <bad text="hi" position="1"/> </result> $ java -jar /usr/share/java/saxon.jar t.xml t.xsl Warning: at xsl:stylesheet on line 2 column 80 of t.xsl: Running an XSLT 1 stylesheet with an XSLT 2 processor <?xml version="1.0" encoding="UTF-8"?> <result> <good text="hello" position="1"/> <good text="hi" position="1"/> </result> The problem is that libxslt uses that template <xsl:template match="text()"> instead of the more specific <xsl:template match="text()[1]">
Created attachment 231727 [details] test data for t.xsl
Created attachment 231728 [details] xsl that shows how xslt does take extra qualifier into account
Fixed in commit cd40951e.