XSLT for everyone with complex state
I am transforming the following XML to generate HTML.
XML
<clause code="section6">
<variable col="1" name="R1C1" row="1">Water</variable>
<variable col="2" name="R1C2" row="1">true</variable>
<variable col="1" name="R2C1" row="2">Gas</variable>
<variable col="2" name="R2C2" row="2"></variable>
<variable col="1" name="R3C1" row="3">Petrol</variable>
<variable col="2" name="R3C2" row="3">true</variable>
<clause>
code>
XSLT
1: <xsl:for-each select="$clause/variable[@col='1']">
2: <xsl:sort select="@row" data-type="number"/>
3: <xsl:variable name="row-id" select="@row"/>
4: <xsl:variable name="row" select="$clause/variable[@row=$row-id]"/>
5: <xsl:if test="$clause/variable[@col='2' and @row=$row-id]='true'">
6: <xsl:value-of name="row-no" select="concat(position(), ') ')"/>
7: <xsl:value-of select="$clause/variable[@col='1' and @row=$row-id]"/>
8: </xsl:if>
9: </xsl:for-each>
code> Transformation works fine and shows the result 1) Water 3) Gasoline
The problem is the serial number. You can see that line 5 is filtering lines that have a 'true' value in col 2 and position () used to display the ordinal. I cannot start the counter in XLST.
I was wondering if I can add a line 5 condition for each in line 1. The result with the above example should be 1) Water 2) Patrol any advice?
source to share
Does it do what you want?
I use the value in column 2, which is true, for each selection. So a position equal to where we are in the selected set of nodes will be 2 not 3
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="/">
<xsl:for-each select="clause/variable[@col='2' and text()='true']">
<xsl:sort select="@row" data-type="number"/>
<xsl:variable name="row-id" select="@row"/>
<xsl:value-of select="concat(position(), ') ')"/>
<xsl:value-of select="/clause/variable[@col='1' and @row=$row-id]"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Although I would probably use templates, preferring for-each, and use current (), so we don't need the row-id variable:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="/">
<xsl:apply-templates select="clause/variable[@col='2' and text()='true']">
<xsl:sort select="@row" data-type="number"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="clause/variable[@col='2' and text()='true']">
<xsl:value-of select="concat(position(), ') ')"/>
<xsl:value-of select="/clause/variable[@col='1' and @row=current()/@row]"/>
</xsl:template>
</xsl:stylesheet>
source to share
I don't think you can express this with a single XPath 1.0 expression.
In XSLT 1.0, I will use keys, and the solution is short, elegant, and efficient :
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:key name="kVarCol2" match="variable[@col=2]" use="@row"/>
<xsl:template match="/*">
<xsl:for-each select="variable[@col='1'][key('kVarCol2', @row)='true']">
<xsl:sort select="@row" data-type="number"/>
<xsl:value-of select="concat('
', position(), ') ', .)"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied to the provided XML document (fixed to be done correctly):
<clause code="section6">
<variable col="1" name="R1C1" row="1">Water</variable>
<variable col="2" name="R1C2" row="1">true</variable>
<variable col="1" name="R2C1" row="2">Gas</variable>
<variable col="2" name="R2C2" row="2"></variable>
<variable col="1" name="R3C1" row="3">Petrol</variable>
<variable col="2" name="R3C2" row="3">true</variable>
</clause>
required, the correct result is obtained :
1) Water 2) Petrol
II. XPath 2.0 solution (one expression):
for $i in 1 to max(/*/*/@row/xs:integer(.))
return
/*/variable[@row eq string($i)]
[@col eq '1'
and
../variable
[@row eq string($i)
and
@col eq '2'
and
. eq 'true'
]
]
/concat('
', position(), ') ', .)
When this XPath 2.0 expression is evaluated on a single XML document (see above), the result is the same desired string :
1) Water 2) Petrol
source to share