XSLT匹配空节点

时间:2011-09-06 19:26:48

标签: xml xslt xsl-stylesheet

我有一个类似以下的XML结构:

<Root>
  <!-- ...other stuff -->
  <Events>
    <Event date="0000-00-00">Event Description etc...</Event>
    <Event date="0000-00-00">Event Description etc...</Event>
    <Event date="0000-00-00">Event Description etc...</Event>
  </Events>
  <!-- ...other stuff -->
</Root>

然后我在样式表中有XSLT,如下所示:

<xsl:variable name="Events" select="/Root/Events/Event" />

<xsl:template match="/">
  <!-- Stuff -->    
  <xsl:apply-templates select="$Events" />
  <!-- Stuff -->    
</xsl:template>

<xsl:template match="Event">
  <!-- Regular Event Template Transformation here -->
</xsl:template>    

<!-- ERROR HAPPENS HERE -->
<xsl:template match="not(node())">
  <p class="message">There are currently no upcoming events</p>
</xsl:template>

我想要做的是有两个模板,一个仅在没有事件时显示。我知道我可以使用带有<xsl:choose><xsl:when>测试的XSLT进行元素计数,并像过程语言一样调用正确的模板,但我正在尝试学习如何执行此操作用模板处理。

我得到的错误是:    表达式的预期结束,找到'('。not - &gt;(&lt; - node())

4 个答案:

答案 0 :(得分:8)

not(node())不是有效的XSLT模式,请尝试:

<xsl:template match="Event">
  <!-- Regular Event Template Transformation here -->
</xsl:template>    

<xsl:template match="Events[not(Event)]">
  <p class="message">There are currently no upcoming events</p>
</xsl:template>

答案 1 :(得分:3)

这可能效果更好

<xsl:template match="*[not(node())]">
  <!-- ... -->

另请参阅此答案:XSLT To remove empty nodes and nodes with -1

答案 2 :(得分:2)

新答案

彻底阅读你的问题,我意识到我的最后解决方案无处可去。我的新答案如下:

由于您需要知道Events内是否有任何元素,因此您需要更改/匹配模板:

<xsl:template match="/">
   <!-- Stuff -->    
   <xsl:apply-templates select="/Root/Events" />
   <!-- Stuff -->    
</xsl:template>

现在,该模板仅匹配填充Events以及所需的Event模板:

<xsl:template="Events[count(child::Event) &gt; 0]">
   <xsl:apply-template select='./Event'/>
</xsl:template>

<xsl:template="Event">
    <!-- some stuff -->
</xsl:template>

现在匹配空Events的模板:

<xsl:template="Events[count(child::Event) = 0]">
   <p class="message">There are currently no upcoming events</p>
</xsl:template>

旧答案

尝试:

<!-- This matches every node with an empty string repr. Maybe you want
     to replace "self::*" to avoid attributes, etc." -->
<xsl:template match="*[string-length(self::*) = 0]">
</xsl:template>

详细说明:

如果我没记错的话,在XPath / XSL中'*'匹配任何类型的节点,即文本节点,元素节点,注释节点,属性节点等......所以在给定的上下文中*[string-length(self::*) = 0]可能与属性匹配;例如,你可能在其他地方有一个select='@*'。因此,此模板可以应用于属性和元素。

如果您确定它与任何属性都不匹配,您可以将其保留原样。但是,我喜欢我的代码表达了正确的想法。因此,如果此模板仅适用于Event元素,我会更改匹配项:

<xsl:template match="Event[string-length(self::*) = 0]">
</xsl:template>

http://www.w3.org/TR/xslt处查看XSLT规范,似乎*仅匹配元素。但是,我会测试它。

答案 3 :(得分:1)

您的处理器抛出错误,因为您的匹配模式会产生布尔值,而不是节点。


尝试此转换(保留所需的变量):

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

    <xsl:variable name="Events" select="/Root/Events/Event"/>

    <xsl:template match="Root">
        <xsl:apply-templates select="$Events
            | Events[not(Event)]"/>  
    </xsl:template>

    <xsl:template match="Event">
        <p class="message">There is an event</p>
    </xsl:template>    

    <xsl:template match="Events">
        <p class="message">There are currently no upcoming events</p>
    </xsl:template>

</xsl:stylesheet>

在您的输入上应用时,生成:

<p class="message">There is an event</p>
<p class="message">There is an event</p>
<p class="message">There is an event</p>

在没有事件的情况下应用于输入时,例如:

<Root>
  <Events/>
</Root>

产生

<p class="message">There are currently no upcoming events</p>