You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@xalan.apache.org by bu...@apache.org on 2002/04/26 12:02:44 UTC

DO NOT REPLY [Bug 8551] New: - incorrect order of returned nodeset from xpath expression

DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG 
RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT
<http://nagoya.apache.org/bugzilla/show_bug.cgi?id=8551>.
ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND 
INSERTED IN THE BUG DATABASE.

http://nagoya.apache.org/bugzilla/show_bug.cgi?id=8551

incorrect order of returned nodeset from xpath expression

           Summary: incorrect order of returned nodeset from xpath
                    expression
           Product: XalanJ2
           Version: 2.3
          Platform: PC
        OS/Version: Other
            Status: NEW
          Severity: Critical
          Priority: Other
         Component: Xalan-Xsltc
        AssignedTo: xalan-dev@xml.apache.org
        ReportedBy: alban.tsui@cognos.com
                CC: alban.tsui@cognos.com


I have the following:
<rowset>
<row><indent>1/<indent><item>A</item></row>
<row><indent>2/<indent><item>B</item></row>
<row><indent>2/<indent><item>C</item></row>
<row><indent>1/<indent><item>D</item></row>
<row><indent>2/<indent><item>E</item></row>
<row><indent>3/<indent><item>F</item></row>
</rowset>

They are the indent levels for trees, so
A
  B
  C
D
  E
    F
I am using a template and xpath (using position()) to work out the item's 
parent position. e.g. For B, its parent is A with position 1, For C, its
parent is A again with position 1. For F its parent is E with position 5.

The result I am after is like:
<rowset>
<row><indent>1/<indent><item>A</item><parent_index>0</parent_index></row>
<row><indent>2/<indent><item>B</item><parent_index>1</parent_index></row>
<row><indent>2/<indent><item>C</item><parent_index>1</parent_index></row>
<row><indent>1/<indent><item>D</item><parent_index>0</parent_index></row>
<row><indent>2/<indent><item>E</item><parent_index>4</parent_index></row>
<row><indent>3/<indent><item>F</item><parent_index>5</parent_index></row>
</rowset>

Using the template in xalan:

<xsl:template match="/rowset">
<rowset>
	<xsl:for-each select="row">
		<xsl:variable name="currindent" select="indent"/>
		<row>
		<indent><xsl:value-of select="indent"/></indent>
		<item><xsl:value-of select="item"/></item>
		<xsl:variable name="pname" select="(preceding-sibling::*
[indent=number($currindent)-1])[last()]"/>

		<subset>
		<xsl:for-each select="preceding-sibling::*[indent=number
($currindent)-1]">
			<item><xsl:value-of select="item"/></item>
		</xsl:for-each>
		</subset>
		<parent_name><xsl:value-of select="$pname/item"/></parent_name>
		<xsl:choose>
			<xsl:when test="count($pname)=0">
				<parent_index>0</parent_index>
			</xsl:when>
			<xsl:otherwise>
				<parent_index><xsl:value-of select="count
($pname/preceding-sibling::row)+1"/></parent_index>
			</xsl:otherwise>
		</xsl:choose>
		</row>
	</xsl:for-each>
</rowset>
</xsl:template>

I have the result:

<?xml version="1.0" encoding="UTF-8"?>
<rowset>
   <row>
      <indent>1</indent>
      <item>A</item>
      <subset/>
      <parent_name/>
      <parent_index>0</parent_index>
   </row>
   <row>
      <indent>2</indent>
      <item>B</item>
      <subset>
         <item>A</item>
      </subset>
      <parent_name>A</parent_name>
      <parent_index>1</parent_index>
   </row>
   <row>
      <indent>2</indent>
      <item>C</item>
      <subset>
         <item>A</item>
      </subset>
      <parent_name>A</parent_name>
      <parent_index>1</parent_index>
   </row>
   <row>
      <indent>1</indent>
      <item>D</item>
      <subset/>
      <parent_name/>
      <parent_index>0</parent_index>
   </row>
   <row>
      <indent>2</indent>
      <item>E</item>
      <subset>
         <item>A</item>
         <item>D</item>
      </subset>
      <parent_name>D</parent_name>
      <parent_index>4</parent_index>
   </row>
   <row>
      <indent>3</indent>
      <item>F</item>
      <subset>
         <item>B</item>
         <item>C</item>
         <item>E</item>
      </subset>
      <parent_name>E</parent_name>
      <parent_index>5</parent_index>
   </row>
</rowset>

which is correct.

Doing the same thing with the same transform compiled in xsltc I got a 
DIFFERENT result:

<?xml version="1.0" encoding="UTF-8"?>
<rowset>
   <row>
      <indent>1</indent>
      <item>A</item>
      <subset/>
      <parent_name/>
      <parent_index>0</parent_index>
   </row>
   <row>
      <indent>2</indent>
      <item>B</item>
      <subset>
         <item>A</item>
      </subset>
      <parent_name>A</parent_name>
      <parent_index>1</parent_index>
   </row>
   <row>
      <indent>2</indent>
      <item>C</item>
      <subset>
         <item>A</item>
      </subset>
      <parent_name>A</parent_name>
      <parent_index>1</parent_index>
   </row>
   <row>
      <indent>1</indent>
      <item>D</item>
      <subset/>
      <parent_name/>
      <parent_index>0</parent_index>
   </row>
   <row>
      <indent>2</indent>
      <item>E</item>
      <subset>
         <item>D</item>
         <item>A</item>
      </subset>
      <parent_name>A</parent_name>
      <parent_index>1</parent_index>
   </row>
   <row>
      <indent>3</indent>
      <item>F</item>
      <subset>
         <item>E</item>
         <item>C</item>
         <item>B</item>
      </subset>
      <parent_name>B</parent_name>
      <parent_index>1</parent_index>
   </row>
</rowset>

The result is wrong because in the <subset> tag the <item>s are returned in 
reverse order in xsltc using the same xpath:
	select="preceding-sibling::*[indent=number($currindent)-1]"
	
In order to get the same result I need to modify/hack my template into the 
following:

<xsl:template match="/rowset">
<rowset>
	<xsl:for-each select="row">
		<xsl:variable name="currindent" select="indent"/>
		<row>
		<indent><xsl:value-of select="indent"/></indent>
		<item><xsl:value-of select="item"/></item>
		<xsl:variable name="pname" select="(preceding-sibling::*
[indent=number($currindent)-1])[1]"/>

		<subset>
		<xsl:for-each select="preceding-sibling::*[indent=number
($currindent)-1]">
			<item><xsl:value-of select="item"/></item>
		</xsl:for-each>
		</subset>
		<parent_name><xsl:value-of select="$pname/item"/></parent_name>
		<xsl:choose>
			<xsl:when test="count($pname)=0">
				<parent_index>0</parent_index>
			</xsl:when>
			<xsl:otherwise>
				<parent_index><xsl:value-of select="count
((preceding-sibling::*[indent=number($currindent)-1])[1]/preceding-sibling::row)
+1"/></parent_index>
			</xsl:otherwise>
		</xsl:choose>
		</row>
	</xsl:for-each>
</rowset>
</xsl:template>

Instead of using "last()" I am using one "1" for the line:
	<xsl:variable name="pname" select="(preceding-sibling::*[indent=number
($currindent)-1])[1]"/>
in order to get the right result in xsltc.


Notice that in xsltc hacked version of template, I could not use the line:
	<parent_index><xsl:value-of select="count($pname/preceding-sibling::row)
+1"/></parent_index>
because in xsltc it seems that it does NOT store the nodeset into $pname 
variable correctly. Therefore I had to use
	<parent_index><xsl:value-of select="count((preceding-sibling::*
[indent=number($currindent)-1])[1]/preceding-sibling::row)+1"/></parent_index>
the full line to get it working.