【问题标题】:xpath : test if node is the only child other than specified ok elementsxpath : 测试 node 是否是指定 ok 元素以外的唯一子节点
【发布时间】:2015-01-15 21:23:57
【问题描述】:

我想编写一个 xsl 模板来检查给定节点是否是唯一的子节点,而不是某些指定的元素:

在这个例子中, 将被更改为 ,因为它是唯一的 节点,并且只有 节点在它之前

<root>
<!-- this is ok, the ok nodes are at the top, followed by only 1 target -->
<mynode>
    <ok1/>
    <ok2/>
    <target/>
</mynode>

<!-- will fail, bad element before target -->
<mynode>
    <ok1/>
    <ok2/>
    <bad/>
    <target/>
</mynode>

<!-- no match, multiple target nodes -->
<mynode>
    <ok1/>
    <ok2/>
    <target/>
    <target/>
</mynode>
</root>

我正在使用这个 xpath:

<xsl:template match="target[not(following-sibling::*)]
                       [not(preceding-sibling::target)]
                       [not(preceding-sibling::*[starts-with(name(), 'bad' or 'hello')])]
                 ">
    <hit>
        <xsl:apply-templates/>
    </hit>
</xsl:template>

在最后一个谓词中,我是否必须明确指出我不想要的任何节点?我可以这样吗

not(preceding-sibling::*[not(starts-with(name(), 'ok'))])

谢谢

【问题讨论】:

  • 如果目标之后有ok元素,是否仍然匹配?
  • @JLRishe 在 OP 的 XPath 表达式中,target 似乎必须是 mynode 的最后一个子节点。只是猜测。
  • @MathiasMüller 好吧,这就是示例似乎表明的内容,但这与问题的描述不一致:“我想编写一个 xsl 模板来检查给定节点是否是唯一的子节点,除了某些指定的元素”。我想我需要提供两个答案。

标签: xml xslt xpath


【解决方案1】:

这个怎么样:

<xsl:template match="target[count(../*) = 
                            count(../*[starts-with(name(), 'ok')]) + 1]">
    <hit>
        <xsl:apply-templates/>
    </hit>
</xsl:template>

解释是匹配target if:

  • 其父元素的所有子元素个数等于
  • 其父元素的所有好子元素的数量加一(本身)

Edit 如果您只想匹配元素,如果它是其父元素的 last 子元素(您在问题中没有这样说,但您的示例表明),您可以在上面的谓词中添加and not(following-sibling::*),或者这里是另一种方法:

<xsl:template match="target[not(following-sibling::*) and 
                            not(preceding-sibling::*[not(starts-with(name(), 'ok'))])
                           ]">

但您似乎已经自己解决了这个问题。

最后,如果您真正想要做的是允许某些特定的 OK 元素并且不匹配基于前缀的名称,您可以为此使用 self::

<xsl:template match="target[count(../*) = 
                            count(../*[self::allgood or self::great]) + 1]">

<xsl:template match="target[not(following-sibling::*) and 
                            not(preceding-sibling::*[not(self::allgood or
                                                         self::great     )]
                               )]">

【讨论】:

    【解决方案2】:
    [not(preceding-sibling::*[starts-with(name(), 'bad' or 'hello')])]
    

    不会工作,因为 'bad' 或 'hello' 是布尔值或字符串 你也不需要使用 double not() 并简单地做

    preceding-sibling::*[starts-with(name(),'ok')]
    

    您还可以创建白名单或黑名单并使用 contains() XPath 函数对其进行迭代,例如:

    <xsl:variable name="oks" select="ok1 ok2 ok3"/>
    

    然后匹配

    preceding-sibling::*[contains($oks, name())]
    

    【讨论】:

    • 您能否解释一下使用您的建议的完整样式表是什么样的?没有双重否定 not 工作,因为这样可能会有前面的兄弟姐妹没有命名为“ok”。另外,我不明白您所说的“是布尔值还是字符串”是什么意思。
    猜你喜欢
    • 2018-09-14
    • 2021-09-19
    • 1970-01-01
    • 2017-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多