你能在XSLT中模拟一个布尔标志吗?

时间:2010-04-14 21:44:21

标签: xslt

我想在xslt脚本中模拟一个标志。这个想法是模板foo设置一个标志(或一个计数器变量,或任何东西),以便可以从模板栏访问它。 Bar不是从foo调用的,而是从公共父模板调用的(否则我会将参数传递给它)。结构是这样的:

<xsl:template match="bla">
  <xsl:apply-templates select="foo"/> <!-- depending on the contents of foo... -->
  <xsl:apply-templates select="bar"/> <!-- ... different things should happen in bar -->
</xsl:template>

非常感谢任何技巧。

4 个答案:

答案 0 :(得分:4)

不是真的......至少在某种意义上你没有尝试这样做。 XSLT中的变量是不可变的,一旦为它们赋值,就无法更改它们,因此尝试多次调用foo来更改标志的值是行不通的。您可以尝试一些模式,这可能会完成您要执行的操作,例如:

<xsl:variable name="myFlag"><xsl:apply-templates select="foo" /></xsl:variable>

<xsl:template match="bla">
      <xsl:apply-templates select="bar" /> <!-- Can use the value of $myFlag --.
</xsl:template>

如果构建模板foo以返回标志的值,那将会有效,但是,如果标志的值意味着随时间变化,那么唯一可以实现此目的的方法是将对foo的调用合并到栏模板。

<xsl:template match="bla">
    <xsl:apply-templates select="bar"> />
</xsl:template>

<xsl:template match="bar">
   <xsl:variable name="flag"><xsl:apply-templates name="foo" /></xsl:variable>

   <xsl:if test="$flag=1">

   </xsl:if>
</xsl:template>

答案 1 :(得分:1)

有很多方法可以做到这一点。例如:

  • 您可以使用像xsl这样的条件结构:if / xsl:choose。
  • 您可以使用变量存储从foo计算的任何内容,并将其作为参数传递给bar上的apply-templates。

真正的XSLT方式是为bar定义不同的模板 - 它们匹配不同的foo案例:

<xsl:template match="bar[../foo[@a='x']]">
  ...
</xsl:template>
<xsl:template match="bar[../foo[@a='y']]">
  ...
</xsl:template>

答案 2 :(得分:0)

如果模板foo将产生输出,则使用输出作为标志的任何解决方案将不起作用。在这种情况下,如果您使用的是基于Java的XSLT处理器(例如Saxon或Xalan),则可以使用可变Java对象。

但请注意,这有其自身的困难。下面给出的转换使用全局标志,这可能不足以满足所有用例。我想在bla模板中实例化该标志并将其作为参数传递给foo和bar,但我无法在Xalan中使用它。另请注意,我在xsl:value-of中调用Java setter,因为否则调用可能会被优化掉(参见Cannot access updated Java object from Saxon XSLT processor)。

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:myflag="java:mypackage.MyFlag">

<xsl:variable name="foo-flag" select="myflag:new()" />

<xsl:template match="bla">
  <xsl:apply-templates select="foo"/> <!-- depending on the contents of foo... -->
  <xsl:apply-templates select="bar"/> <!-- ... different things should happen in bar -->
</xsl:template>

<xsl:template match="foo">
  <xsl:choose>
     <xsl:when ...>
       <xsl:value-of select="myflag:set($foo-flag, true())" />
       ...
     </xsl:when>
     <xsl:otherwise>
       <xsl:value-of select="myflag:set($foo-flag, false())" />
       ...
     </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="bar">
  <xsl:choose>
     <xsl:when test="myflag:get($foo-flag)">
       ...
     </xsl:when>
     <xsl:otherwise>
       ...
     </xsl:otherwise>
  </xsl:choose>
</xsl:template>

</xsl:transform>

最基本版本中的MyFlag类只是一个可变的布尔包装器。

public class MyFlag {
private boolean flag;
public void set(boolean flag){
  this.flag = flag;
}
public boolean get(){ return flag; }
}

答案 3 :(得分:0)

这使用您在问题中提到的方法:传递参数,从foo到bar。注意:这假定每个foo下方只有一个bla,否则每个bar元素将永远或多次调用条形模板。

<xsl:template match="bla">
    <xsl:apply-templates select="foo" />
</xsl:template>

<xsl:template match="foo">
   ...    
   <xsl:apply-templates select="../bar">
     <xsl:with-param name="flag" select="..." />
   </xsl:apply-templates />
</xsl:template>