XPath-获取没有特定类型的子节点的节点


68

XML:/A/B/A

我想获取A没有任何子节点的所有节点B

我试过了

/A[not(B)]  
/A[not(exists(B))]

没有成功

/*[local-name()="A" and .... ]如果可能,我更喜欢使用语法的解决方案。有什么想法可行吗?

澄清。xml看起来像:

<WhatEver>
  <A>
    <B></B>
  </A>
</WhatEver> 

要么

<WhatEver>
  <A></A>
</WhatEver>

2
如果没有看到您的XML,我会说“ / A [not(B)]”是必经之路。怎么了
Tomalak

而且,应该只有一个根元素,因此您要么获取所有XML,要么不获取任何XML。也许//A[not(B)] or /*/A[not(B)]吧?
阿尔玛

使用“抽象”语法/ A / B,在“ XML:”之后的第一行,我的意思是<A> <B>,就像Tomalak和alamar认为的那样。
Martin Bring

或<A> <B> <B> <A>或<A> <A>准确地说。
Martin Bring

抱歉,结尾为<A> <B> </ B> </A>或<A> </A>。
Martin Bring

Answers:


50

也许 *[local-name() = 'A' and not(descendant::*[local-name() = 'B'])]吧?

另外,应该只有一个根元素,因此对于/A[...]您来说,要么取回所有XML,要么不取回所有XML。也许//A[not(B)]还是/*/A[not(B)]

我真的不明白为什么/A[not(B)]对您不起作用。

~/xml% xmllint ab.xml
<?xml version="1.0"?>
<root>
    <A id="1">
            <B/>
    </A>
    <A id="2">
    </A>
    <A id="3">
            <B/>
            <B/>
    </A>
    <A id="4"/>
</root>
~/xml% xpath ab.xml '/root/A[not(B)]'
Found 2 nodes:
-- NODE --
<A id="2">
    </A>
-- NODE --
<A id="4" />

我可以确认,/ A [not(B)]并不总是如广告所示。我有一个在XMLspear中使用Xalan的示例,其中<xsl:for-each select =“ exsl:node-set($ theFields)/ * [name()='field'] [not(child :: ** name()= 'disabled'])]]“> [在此处进行填充] </ xsl:for-each>从<xsl:for-each select =” exsl:node-set($ FLD)/ field [not(disabled) ]“> [在此处进行填充] </ xsl:for-each>实际上,在相同情况下,使用select =” exsl:node-set($ theFields)/ * [name()='field']“会产生输出,但完全没有选择=“ exsl:node-set($ theFields)/ field”。
约翰·史密斯,

@MichaelKupietz为什么不为此提出一个新问题?
alamar

在某个时候,当我有时间将大型XSLT缩减到最小的工作演示时,我可能会这样做。但是,在这一点上,我只是在回应暗示/ A(not [B])应该执行OP所没有执行的操作的评论,仅仅是因为我观察到OP所做的相同操作。显然,至少并非总是如此。该确认可能会使此页面的将来的一些读者感到有些困惑。
约翰·史密斯,

18

试试这个"/A[not(.//B)]"或这个"/A[not(./B)]"


1
“尝试这个”答案对Stackoverflow来说价值不高,因为它们对教育和授权OP和成千上万的未来研究人员没有多大作用。
mickmackusa

11

第一个/导致XPath从文档的根开始,我怀疑那是您的意图。

也许您的意思是// A [not(B)],它将在任何级别上找到文档中所有没有直接B子级的A节点。

也许您已经在一个包含A节点的节点上,在这种情况下,您只希望A [not(B)]作为XPath。


3

如果您尝试从根目录的层次结构中的任意位置获取A,则此方法有效(对于xslt 1.0以及2.0,以防在xslt中使用它)

//descendant-or-self::node()[local-name(.) = 'a' and not(count(b))]

或者你也可以

//descendant-or-self::node()[local-name(.) = 'a' and not(b)]

或者也

//descendant-or-self::node()[local-name(.) = 'a' and not(child::b)]

xslt中没有n种方法可以实现相同的目的。

注意:XPath区分大小写,因此,如果您的节点名称不同(我确定没有人会使用A,B),那么请确保大小写匹配。


仅供参考,问题是关于XPath,而不是XSLT。它们是不同的(尽管相关)技术。否则,您的答案在技术上是正确的。顺便说一句,“ / root / A [not(B)]”就像@Alamar所说的一样工作。;-)
Cerebrus

感谢您的更正。我的最后一行是xpaths。已编辑帖子。至于“ / root / A [not(B)]”,我已经成功运行了它。但由于它不适用于Martin,因此发布了其他xpath。其中也提到了区分大小写。
SO用户

一个人如何选择除了B之外还有其他直系孩子的所有A ?(A和所有子节点,只要它们仅包含一个或多个B元素)
CodeManX 2014年

2

用这个:

/*[local-name()='A' and not(descendant::*[local-name()='B'])]
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.