如何在xsl if语句中使用xsl变量

4

我正在尝试将xsl变量的值赋给xml文件中的一个新节点。这段代码可以工作,但是当"lbi:GetCoordinates(PVAL)"的值为空时,它会添加一个空的PROP/PVAL节点:

<xsl:template match="PROP" mode="Geocode">
<PROP NAME="Geocode">
    <PVAL>
      <xsl:value-of select="lbi:GetCoordinates(PVAL)"/>
    </PVAL>
 </PROP>
 </xsl:template>

由于我不想要任何空节点,因此我只在“lbi:GetCoordinates(PVAL)”的值不为空时添加新节点。我尝试的方法是将该值分配给一个变量并测试该变量,如下所示。不幸的是,即使“lbi:GetCoordinates(PVAL)”返回非空值,我也没有得到新的PROP节点。

<xsl:template match="PROP" mode="Geocode">
<xsl:variable name="coords" select="'lbi:GetCoordinates(PVAL)'"/>
<xsl:if test="not(string-length(coords) = 0)">
  <PROP NAME="Geocode">
    <PVAL>
      <xsl:value-of select="coords"/>
    </PVAL>
  </PROP>
</xsl:if>
</xsl:template>

请问有人能指导我方向,或者提出更好的实现方式吗?

源xml如下:

<RECORD>
<PROP name="PostCode">
<PVAL>N11 1NN</PVAL>
</PROP>
</RECORD>

模板可以这样引用:

<xsl:template match="RECORD">
<xsl:copy>
  <xsl:apply-templates select="PROP[@NAME='PostCode']" mode="Geocode"/>
</xsl:copy>

lbi:GetCoordinates() 方法位于一个作为 xml 命名空间添加的外部 .Net 程序集中。


使用这种方法是可行的:

<xsl:template match="PROP[string-length(lbi:GetCoordinates(PVAL))>0]" mode="Geocode">
  <PROP NAME="Geocode">
    <PVAL>
      <xsl:value-of select="lbi:GetCoordinates(PVAL)"/>
    </PVAL>
  </PROP>

现在的问题是,lbi:GetCoordinates方法被调用了两次,但实际上只需要调用一次。源xml可能有100,000多个需要进行地理编码的元素,因此这是一个非常棘手的问题。这表明我之前使用的xsl:variable表达式是不正确的,变量始终为空。


请查看我的答案,可能会有一个解决方案。非常重要的是要知道 lbi:GetCoordinates() 函数返回什么 -- 请具体说明。 - Dimitre Novatchev
3个回答

4
<xsl:variable name="coords" select="'lbi:GetCoordinates(PVAL)'"/> 
<xsl:if test="not(string-length(coords) = 0)"> 

这几乎是正确的。唯一的问题是在lbi:GetCoordinates(PVAL)周围的引号。这些将扩展函数的返回值转换为调用此函数的表达式的字符串。由于该字符串的长度显然大于0,第二行的测试将始终为真。
从这里开始,我假设lbi:GetCoordinates()函数返回一个字符串或原子值(而不是节点或节点集),因为您没有提到函数的返回类型,但这非常重要!
你想要的是(请注意现在缺少引号!):
<xsl:variable name="coords" select="lbi:GetCoordinates(PVAL)"/> 
<xsl:if test="not(string-length(coords) = 0)"> 

但即使这样还是有点笨重。

解决方案:利用XSLT模板匹配模式的威力,完全避免模板内部的条件逻辑:

<xsl:template match="PROP[string-length(lbi:GetCoordinates(PVAL))]"
     mode="Geocode">
  <PROP NAME="Geocode">                     
    <PVAL>                     
      <xsl:value-of select="lbi:GetCoordinates(PVAL)"/>                     
    </PVAL>                     
   </PROP>
 </xsl:template> 

不用担心 lbi:GetCoordinates(PVAL) 函数会被调用两次,因为一个优化良好的 XSLT 处理器只会调用一次。您可以进行一些测试以查看是否如此。在最坏的情况下,如果 XSLT 处理器很笨,并且调用了两次该函数,则使用上面更繁琐的代码。

0
如果你的源XML文件看起来有点像这样:
<PROP>
  <lbi:GetCoordinates(PVAL)>sometext</lbi:Getcoordinates(PVAL>
</PROP>

这个应该可以解决问题:

<xsl:template match="PROP[string-length(lbi:GetCoordinates(PVAL))>0]" mode="Geocode">
    <PROP NAME="Geocode">
        <PVAL>
          <xsl:value-of select="lbi:GetCoordinates(PVAL)"/>
        </PVAL>
     </PROP>
</xsl:template>

我将匹配子句更改为早期过滤,您也可以尝试将if语句从not(string-length()=0)更改为string-length>0

目前我没有测试环境,请考虑包含您的源XML,因为这对于构建XSLT的确切方式至关重要


谢谢您,我已经扩展了原来的问题并提供了有关源XML的信息。 - Jason
这种方法确实可行,但每次调用lbi:GetCoordinates方法两次的要求是不可取的。 - Jason

0
尝试使用string-length(coords) > 0代替您的条件。

谢谢,但是我用这个得到了相同的结果。 - Jason

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接