首页 文章

xpath:测试节点是否是指定ok元素以外的唯一子节点

提问于
浏览
1

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

在此示例中,<target />将更改为<hit />,因为它是唯一的<target />节点,并且只有<ok />节点位于其前面

<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'))])

谢谢

2 回答

  • 3

    这个怎么样:

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

    解释是匹配 target 如果:

    • 其父级的所有子元素的数量等于

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

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

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

    但你似乎已经想到了自己的一个 .

    Lastly, 如果您真正想要做的是允许某些特定的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     )]
                                   )]">
    
  • 0
    [not(preceding-sibling::*[starts-with(name(), 'bad' or 'hello')])]
    

    将不会工作'坏'或'你好'是布尔值或字符串你也不需要使用双not()而只是做

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

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

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

    然后匹配

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

相关问题