【问题标题】:XSLT matching empty nodesXSLT 匹配空节点
【发布时间】:2011-09-06 19:26:48
【问题描述】:

我的 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 与 &lt;xsl:choose&gt;&lt;xsl:when&gt; 测试一起使用来计算元素并像在过程语言中那样调用正确的模板,但我正在尝试学习如何通过模板处理来做到这一点。

我得到的错误是: 表达式的预期结尾,发现'('。不是-->(

【问题讨论】:

    标签: xml xslt xsl-stylesheet


    【解决方案1】:

    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>
    

    【讨论】:

    • 第一个模板将匹配 Event 节点和(任何)子节点。第二个是相反的。我认为它不能解决 OP 的问题。
    • @Dimitre 不要认为是最精确和正确的。如果 OP 不更改模板的应用方式(如我的回答所示),则永远不会执行第二个模板。
    • @_empo:@Max_Toro 提供了一个完整的解决方案——OP 应该只使用它(例如复制和粘贴)。
    • 为了清楚起见,对于任何试图做同样事情的人来说,这仅在我在我的 $Events 变量中使用 /Root/Events 而不是 /Root/Events/Event 如我的问题所述时才有效。所以,我改变了它。附带说明一下,在我的情况下,我的 Events 节点实际上是 &lt;in:result name="GetEvents"&gt; 所以我需要将第一个模板更改为:&lt;xsl:template match="in:result[@name='GetEvents' and not(Event)]"&gt; 以使其工作。它有效。 ^_^ 谢谢。
    • 这太酷了!我使用稍微不同的版本作为无法识别节点的后备,因此任何带有子节点 (select="") 的内容都呈现为 div 块和任何叶节点 (select="*[not( i>)"] 被呈现为 key=value...
    【解决方案2】:

    这可能会更好

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

    在这里也可以看到这个答案:XSLT To remove empty nodes and nodes with -1

    【讨论】:

    • 这行得通,但只是好奇......据我了解,星代表一组Event 对吗?那么这句话是否匹配任何没有节点的Event 或没有节点的“The Set”?
    • 嗯,实际上又想起来了,我很惊讶它确实有效......我只是想更正你的语法,而不是语义
    • 这是匹配任何元素(可以是 RootEventsEvent)子节点(元素或文本)。它部分轻松解决了OP的问题。
    • 我明白了。所以,它是没有节点的任何东西。它可以工作......但我相信在我的具体情况下不会......因为Events 节点将具有属性节点。
    【解决方案3】:

    新答案

    彻底阅读您的问题后,我意识到我最后的解决方案无济于事。我的新答案如下:

    由于您需要知道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 规范,* 似乎只匹配元素。不过,我会测试一下。

    【讨论】:

    • 你能帮忙解释一下避免属性是什么意思吗?这是否意味着如果有一个Event 里面没有内容,它也会被匹配?
    • 用更多细节更新答案。
    【解决方案4】:

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


    试试这个转换(保留所需的变量):

    <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>
    

    【讨论】:

    • 我试过这个......我发现你不能将它与 $Events 变量一起使用,例如match="$Events[not(Event)]"我的结构需要使用一个变量,不幸的是......我给出的示例被简化以反映我要返回的结构。
    • 现在检查我的答案。我已经编辑了模板以便使用该变量。希望这是您要搜索的内容,否则我认为我需要有关您的要求的更清晰的信息。
    • 我认为这是我对“匹配”参数如何工作的误解。我试图这样做:&lt;xsl:template match="$Events[not(Event)]"&gt; 但它不喜欢$
    • 是的,我意识到...我已经更改了变量的值。我猜一开始我希望匹配“null”,但当我想到它时它并没有多大意义。
    • 仅在 XSLT 2.0 中允许在模板匹配中使用变量
    猜你喜欢
    • 2018-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多