ChatGPT解决这个技术问题 Extra ChatGPT

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

XML:/A/B/A

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

我试过了

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

没有成功

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

澄清。 xml 看起来像:

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

或者

<WhatEver>
  <A></A>
</WhatEver>
如果没有看到您的 XML,我会说“/A[not(B)]”是要走的路。那有什么问题?
此外,应该只有一个根元素,因此您要么取回所有 XML,要么没有。也许//A[not(B)] or /*/A[not(B)]
使用“抽象”语法 /A/B,在“XML:”之后的第一行,我的意思是 ,正如 Tomalak 和 alamar 所想的那样。

a
alamar

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

此外,应该只有一个根元素,因此对于 /A[...],您要么获取所有 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 的示例,其中 [DO STUFF HERE] [DO STUFF HERE] 事实上,在同样的情况下,使用 select="exsl:node-set($theFields)/*[name()='field']" 会产生输出,但 select="exsl:node-set($theFields)/field" 根本没有。
@MichaelKupietz 为什么不为此提出一个新问题?
在某个时候,当我有时间将一个巨大的 XSLT 缩减为最低限度的工作演示时,我可能会这样做。不过,在这一点上,我只是回应暗示 /A(not[B]) 应该做 OP 所说的不应该做的评论,仅仅是因为我观察到了 OP 做的同样的事情。显然,至少并非总是如此。该确认可能会使此页面的某些未来读者感到困惑。
e
eozzy

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


“试试这个”的答案在 Stackoverflow 上的价值很低,因为它们对教育/授权 OP 和成千上万的未来研究人员的作用很小。
A
AnthonyWJones

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

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

或者您可能已经在一个包含 A 节点的节点上,在这种情况下您只需要 A[not(B)] 作为 XPath。


S
SO User

如果您试图从根目录中获取层次结构中的 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 中没有多种方法可以实现相同的目标。

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


仅供参考,问题是关于 XPath,而不是 XSLT。它们是不同(尽管相关)的技术。否则,您的答案在技术上是正确的。顺便说一句,“/root/A[not(B)]”就像@Alamar 提到的那样工作得很好。 ;-)
感谢您的指正。我的意思是我最后一行中的 xpaths。已编辑帖子。至于“/root/A[not(B)]”我已经运行成功了。但是还发布了备用 xpath,因为它不适用于 Martin。这也是易提到的区分大小写。
一个人如何选择除 B 以外的所有直系孩子的 A? (A 和所有子节点,只要它们只包含一个或多个 B 元素)
C
Cobaia

用这个:

/*[local-name()='A' and not(descendant::*[local-name()='B'])]