如何在<xsl:if>语句中保留类型信息?</xsl:if>

时间:2013-03-04 23:00:19

标签: xslt xslt-2.0 saxon

我正在使用Saxon 9.4和XSLT 2.0

我的样式表中有以下代码段: -

<xsl:template name="some_template">
  <xsl:param name="some_param" as="xs:integer?"/>
</xsl:template>

这基本上是一个接受可选整数参数的模板。但是,当我尝试这样称呼时,

<xsl:call-template name="some_template>
  <xsl:with-param name="some_param">
    <xsl:if test="some_condition">
      <xsl:value-of select="xs:integer(./@attr div 20)"/>
    </xsl:if>
  </xsl:with-param>
</xsl:call-template>

我收到一条错误消息: -

Validation error 
  FORG0001: Cannot convert zero-length string to an integer

但是,以下两个样式表不会给我一个错误: -

<xsl:call-template name="some_template>
  <xsl:with-param name="some_param">
    <xsl:value-of select="xs:integer(./@attr div 20)"/>
  </xsl:with-param>
</xsl:call-template>

<xsl:variable name="dummy" as="xs:integer?">
  <xsl:if test="some_condition">
    <xsl:value-of select="xs:integer(./@attr div 20)"/>
  </xsl:if>
</xsl:variable>
<xsl:call-template name="some_template>
  <xsl:with-param name="some_param" select="$dummy"/>
</xsl:call-template>

很明显,整个街区没有保留类型信息。知道如何让第一件事工作吗?第三个样式表做了我想要的语义,但我宁愿不去创建(几个)虚拟变量只是为了能够做到这一点。

谢谢!

3 个答案:

答案 0 :(得分:1)

我认为当你的<xsl:if>为假时错误意味着你的参数没有分配值。您可以尝试以下解决方案之一:

默认值

您是否尝试为<xsl:param>设置默认值?

<xsl:template name="some_template">
  <xsl:param name="some_param" select="-1" as="xs:integer?" />
</xsl:template>

管理false案例

使用XPath2.0 if-then-else expression调用模板时始终设置值:

<xsl:call-template name="some_template>
  <xsl:with-param name="some_param" select="
     if (some_condition) 
     then xs:integer(./@attr div 20)
     else -1"
  />
</xsl:call-template>

我使用-1作为false案例的值。

答案 1 :(得分:1)

此转化

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema">
 <xsl:output method="text"/>

 <xsl:template match="/*">
    <xsl:call-template name="some_template">
      <xsl:with-param name="some_param" select=
       "if(some_condition)
          then xs:integer(@attr div 20)
          else ()
      "/>
    </xsl:call-template>
 </xsl:template>

 <xsl:template name="some_template">
  <xsl:param name="some_param" as="xs:integer?"/>
  XXX
</xsl:template>
</xsl:stylesheet>

应用于以下每个XML文档时:

<t attr="20">
 <some_condition/>
</t>

<t>
 <some_condition/>
</t>

<t attr="20">
</t>

<t>
</t>

产生想要的正确结果(不会产生任何异常):

  XXX

答案 2 :(得分:1)

我并不完全清楚这里发生了什么,但很清楚的是如何改进你的代码,这样就不会那么混乱了。使用您编写的代码,在真实情况下,您正在计算double,将其转换为整数,将整数转换为文本节点,将其包装在文档节点中,将文档节点作为参数传递,将此雾化为无类型接收端的原子,因为期望的类型是原子的,然后将无类型的原子值转换为整数。所有这一切都应该有效,但是非常迂回,并且很容易通过xsl:with-param上的“as =”xs:integer“”来避免。

在false的情况下,您传递的文件节点没有子节点,并将其转换为xs:integer?将失败 - 它不会转换为空序列。所以,尽管你说的话,我认为它在错误的道路上失败了。