4

我有一个如下的 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>

我想做的是有两个模板,一个只在没有事件时显示。我知道我可以使用 XSLT<xsl:choose><xsl:when>测试来计算元素并调用正确的模板,就像我在过程语言中所做的那样,但我正在尝试学习如何通过模板处理来做到这一点。

我得到的错误是: 预期的表达式结束,找到'('。不是-->(<-- node())

4

4 回答 4

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>
于 2011-09-06T20:37:22.217 回答
3

这可能会更好

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

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

于 2011-09-06T19:30:09.660 回答
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='@*'其他地方有一个。所以这个模板可以应用于属性和元素。

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

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

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

于 2011-09-06T19:31:43.283 回答
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>
于 2011-09-06T19:50:26.903 回答