Jump to content

Test To Compare The Value Of The Current Node With The Previous Node.


howardcole

Recommended Posts

Hi! Here is a newbie question that will probably make you cringe...I am trying to find a test that will compare the value of the id of the current row with the id of the previous row. Here is an extract from my data

<table>	<row>		<operator_id>1</operator_id>		<name>tom</name>	</row>	<row>		<operator_id>2</operator_id>		<name>######</name>	</row>	<row>		<operator_id>2</operator_id>		<name>harry</name>	</row></table>

My first attempt to distinguish rows with the same Id as the previous row was as follows:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">  <xsl:template match="/table">	   <xsl:apply-templates select="row"/>  </xsl:template>  <xsl:template match="row">	<xsl:choose>	  <xsl:when test="operator_id = /table/row[position()-1]/operator_id">		<tr style="color: green">		  <td>			<xsl:value-of select="operator_id"/>		  </td>		  <td>			<xsl:value-of select="name"/>		  </td>		</tr>		</xsl:when>	  <xsl:otherwise>		<tr style="color: red">		  <td>			<xsl:value-of select="operator_id"/>		  </td>		  <td>			<xsl:value-of select="name"/>		  </td>		</tr>		</xsl:otherwise>	</xsl:choose>  </xsl:template></xsl:stylesheet>

This did not work - I think this is because this would always return false because the current row will never be the previous row.So how do I compare the values rather than the nodes?ThanksHoward Cole

Link to comment
Share on other sites

Try it like that:

<xsl:variable name="curPos" value="position()" /><xsl:when test="string(operator_id) = string(../row[$curPos - 1]/operator_id)">

Link to comment
Share on other sites

Try it like that:
<xsl:variable name="curPos" value="position()" /><xsl:when test="string(operator_id) = string(../row[$curPos - 1]/operator_id)">

Fantastic! That put me on the right track. The finished XSL is below for anyone interested.Thanks very much boen_robot!I have one question. How come you need the variable? If I substitute the variable with the following it doesn't work:
<xsl:when test="string(operator_id) = string(../row[position() - 1]/operator_id)">

Howard Cole.Working version:

<?xml version="1.0"?><xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">  <xsl:template match="/table">	<html>	  <body>		<table>		  <xsl:apply-templates select="row"/>	  		</table>	  </body>	</html>	  </xsl:template>  <xsl:template match="row">	<xsl:variable name="curPos" select="position()" />	<xsl:choose>	  <xsl:when test="string(operator_id) = string(../row[$curPos - 1]/operator_id)">		<tr style="color: green">		  <td>			<xsl:value-of select="operator_id"/>		  </td>		  <td>			<xsl:value-of select="name"/>		  </td>		</tr>	  </xsl:when>	  <xsl:otherwise>		<tr style="color: red">		  <td>			<xsl:value-of select="operator_id"/>		  </td>		  <td>			<xsl:value-of select="name"/>		  </td>		</tr>	  </xsl:otherwise>	</xsl:choose>  </xsl:template></xsl:stylesheet>

Link to comment
Share on other sites

Your attempt does not work as the position() function returns the context position for the context node and with ../row[position() - 1] the context node is the 'row' element you are applying the predicate [position() - 1] to. So you have to understand that each expression changes the context node and that way what the position function relates to.And you don't need all those attempts with position, XPath allows you to simply access any preceding sibling directly with one expression so the following stylesheet suffices:

<xsl:stylesheet  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  version="1.0">    <xsl:output  method="html" indent="yes"/>  <xsl:template match="/table">	<html>	  <body>		<table>		  <xsl:apply-templates select="row"/>	  		</table>	  </body>	</html>	  </xsl:template>    <xsl:template match="row">	<tr>	  <xsl:attribute name="style">		<xsl:choose>		  <xsl:when test="operator_id = preceding-sibling::row[1]/operator_id">			<xsl:text>color: green;</xsl:text>		  </xsl:when>		  <xsl:otherwise>			<xsl:text>color: red;</xsl:text>		  </xsl:otherwise>		</xsl:choose>	  </xsl:attribute>	  <td>		<xsl:value-of select="operator_id"/>	  </td>	  <td>		<xsl:value-of select="name"/>	  </td>	</tr>  </xsl:template></xsl:stylesheet>

Link to comment
Share on other sites

Your attempt does not work as the position() function returns the context position for the context node and with ../row[position() - 1] the context node is the 'row' element you are applying the predicate [position() - 1] to. So you have to understand that each expression changes the context node and that way what the position function relates to.
Hi Martin, that statement is hurting my head. Please would you be so kind to explain further...When the variable $curpos is calculated on the third row, the value of $curpos is 2 (assuming indexing from 1), so the string(../row[$curpos-1]/operator_id) returns the operator_id from the 2nd row.However, when evaluated as string(../row[position() - 1]/operator_id), what is the value of position() and what is the context node then?Thanks.Working xsl snippet with variable.
 <xsl:template match="row">	<xsl:variable name="curPos" select="position()" />	<xsl:choose>	  <xsl:when test="string(operator_id) = string(../row[$curPos - 1]/operator_id)">

Broken xsl snippet with inline position()

 <xsl:template match="row">	<xsl:variable name="curPos" select="position()" />	<xsl:choose>	  <xsl:when test="string(operator_id) = string(../row[position() - 1]/operator_id)">

XML Data

<table>	<row>		<operator_id>1</operator_id>		<name>tom</name>	</row>	<row>		<operator_id>2</operator_id>		<name>######</name>	</row>	<row>		<operator_id>2</operator_id>		<name>harry</name>	</row></table>

Link to comment
Share on other sites

With ../row[position() - 1] you first select all 'row' child elements of the parent (selected with ..). Then the predicate in square brackets is applied to each selected 'row' element and position() in that predicate simply gives the position of each 'row' element in the node-set. So for the first 'row' element the expression '1 - 1' is computed which gives 0, for the second 'row' element the expression '2 - 1' is computed which gives 1 and so on. If a predicate evaluates to an number, then, as stated in http://www.w3.org/TR/xpath/#predicates, "the result will be converted to true if the number is equal to the context position and will be converted to false otherwise". That way your expression ../row[position() - 1] does not select any nodes.

Link to comment
Share on other sites

What Martin is trying to explain is that the returned value from position() changes, depending on where you are currently, in the XPath.When you apply position() as a predicate to an element, you're essentially testing the element against itself, and by changing its position, you're always not selecting it. You're not testing the element against the base context node, but from the current context node.BTW, that reminds me... there is an alternative, variable free way to get the same result. I don't know if it's more efficient, though I'd guess yes. Simply use the current() function. That function returns the current base context node, so applying position() - 1 over it should work, i.e.

<xsl:when test="string(operator_id) = string(../row[current()/position() - 1]/operator_id)">

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...