XSLT for-each具有复杂条件

时间:2012-03-29 02:47:11

标签: xslt foreach

我正在转换XML以生成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>

<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>

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>
转换工作正常并显示结果 1)水3)汽油

问题是序列号。您可以在第5行过滤器行中看到条件,这些行在 col 2 中只有'true'值,而position()用于显示序列号。我不能在XLST中运行计数器。

我想知道我是否可以在第1行添加第5行的条件。上面示例的结果应该是 1)水2)巡逻任何建议?

2 个答案:

答案 0 :(得分:3)

这样做你想要的吗?

我驱动col 2上的for-each选项为true。那样的位置,等于我们在所选节点集中的位置将等于2而不是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>

虽然我可能会使用优先于for-each的模板并使用current(),因此我们不需要row-id变量:

<?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>

答案 1 :(得分:2)

我认为你不能用一个XPath 1.0表达式来表达它。

在XSLT 1.0中,我将使用密钥,解决方案变得简短,优雅和高效

<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('&#xA;', position(), ') ', .)"/>
    </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

当对提供的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>

产生了想要的正确结果

1) Water
2) Petrol

<强> II。 XPath 2.0(单表达式)解决方案:

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('&#xA;', position(), ') ', .)

在同一个XML文档(上图)上评估此XPath 2.0表达式时,结果是相同的所需字符串

1) Water 
2) Petrol