XSLT:嵌套for-each和动态变量

时间:2012-04-18 18:40:46

标签: xslt

这是我的XML和XSLT代码

<root>
    <act>
        <acts id>123</acts>
    </act>
    <comp>
        <comps id>233</comps>
    </comp>
</root>


<xsl:for-each select="act/acts">
    <xsl:variable name="contactid" select="@id"/>
    <xsl:for-each select="root/comp/comps">
        <xsl:variable name="var" select="boolean(contactid=@id)"/>
    </xsl:for-each>
    <xsl:choose>
        <xsl:when test="$var='true'">
          . . . do this . . .
        </xsl:when>
        <xsl:otherwise>
          . . . do that . . .
        </xsl:otherwise>
    </xsl:choose>
</xsl:for-each>

我想动态地为var分配true或false,并在<xsl:choose>内使用它进行布尔测试。我希望这有助于找到一个更好的解决方案来摆脱for-each

2 个答案:

答案 0 :(得分:3)

首先要注意的是XSLT中的变量是不可变的,初始化后不能更改。 XSLT的主要问题是您在 xsl:for-each 块中定义变量,因此它只存在于该块的范围内。它不是一个全局变量。每次只能在 xsl:for-each

中使用新变量

从查看您的XSLT看起来您希望迭代 act 元素并执行某个操作,具体取决于 comps 元素是否存在具有相同值。另一种方法是定义一个键来查找 comps 元素,如此

<xsl:key name="comps" match="comps" use="@id" />

然后您可以简单地检查 comps 元素是否存在(假设您位于 act 元素上。

<xsl:choose>
   <xsl:when test="key('comps', @id)">Yes</xsl:when>
   <xsl:otherwise>No</xsl:otherwise>
</xsl:choose>

这是完整的XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:key name="comps" match="comps" use="@id" />

   <xsl:template match="/root">
      <xsl:apply-templates select="act/acts" />
   </xsl:template>

   <xsl:template match="acts">
      <xsl:choose>
         <xsl:when test="key('comps', @id)"><res>Yes</res></xsl:when>
         <xsl:otherwise><res>No</res></xsl:otherwise>
      </xsl:choose>
   </xsl:template>
</xsl:stylesheet>

应用于以下(格式良好的)XML

<root>
   <act>
      <acts id="123"/>
   </act>
   <comp>
      <comps id="233"/>
   </comp>
</root>

以下是输出

没有

但是,通常最好在XSLT中避免使用条件语句,如 xsl:choose xsl:if 。相反,您可以构建XSLT以使用模板匹配。这是替代方法

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:key name="comps" match="comps" use="@id" />

   <xsl:template match="/root">
      <xsl:apply-templates select="act/acts" />
   </xsl:template>

   <xsl:template match="acts[key('comps', @id)]">
      <res>Yes</res>
   </xsl:template>

   <xsl:template match="acts">
      <res>No</res>
   </xsl:template>
</xsl:stylesheet>

当应用于相同的XML时,输出相同的结果。请注意,在匹配 comps 存在的情况时,行为节点的更具体模板将具有优先权。

答案 1 :(得分:1)

你的xml文件中有一些错误,但假设你的意思是:

<root>
    <act><acts id="123"></acts></act>
    <comp><comps id="233"></comps></comp>
</root>

这是一个完整的解决方案:

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 

    <xsl:template match="/">
        <doc>   
           <xsl:apply-templates select="root/comp/comps"/>  
        </doc>
    </xsl:template>

    <xsl:template match="root/comp/comps"> 
        <xsl:variable name="compsid" select="@id"></xsl:variable>
        <xsl:choose>
            <xsl:when test="count(/root/act/acts[@id=$compsid])&gt;0">Do This</xsl:when>
            <xsl:otherwise>Do That</xsl:otherwise>
        </xsl:choose>
    </xsl:template> 

</xsl:stylesheet>