使用XPath(.NET),我正在尝试选择所有不包含任何文本节点的节点。
鉴于此文件:
<root>
<node1>
<node1a>Node 1A</node1a>
</node1>
<node2>Node 2</node2>
<node3>
<node3a>Node 3A</node3a>
<node3b></node3b>
</node3>
<node4></node4>
<node5>
<node5A></node5A>
</node5>
</root>
我想要获取节点:
<node3b></node3b>
<node4></node4>
<node5>
<node5A></node5A>
</node5>
请注意,重叠的子树是合并的,因此不应单独返回node5A。
我希望这可以解决问题,但由于某种原因(当有人指出它时可能很明显)它不会:
//*[count(//text()) = 0]
注意:我正在使用XPath tester来尝试。
答案 0 :(得分:2)
Arg ......就在发布时,解决方案就出现了:
//*[count(.//text()) = 0]
说明:条件count(//text()) = 0
计算根目录中的所有文本节点,该节点始终大于零。要从当前节点计数,我需要在点前缀count(.//text()) = 0
请注意,@ jvverde正确地指出节点可以在结果集中多次出现。所以这个表达式与我提到的条件不完全匹配,因为node5A在那里两次:
<node3b></node3b>
<node4></node4>
<node5>
<node5A></node5A>
</node5>
<node5A></node5A>
答案 1 :(得分:1)
你也可以使用//*[.='']
,因为空元素应该有空字符串值。
答案 2 :(得分:1)
假设您的结果示例确实是您想要的(这不完全符合标题中的陈述)上面的建议
//*[count(.//text()) = 0]
或首选方式
//*[not(.//text())]
不起作用,因为结果不符合您的预期
<node3b />
<node4 />
<node5>
<node5A />
</node5>
<node5A /> <!-- this node is not present in your example -->
如果你想要的是所有子树而没有任何文本节点没有包含在其他结果子树中,解决方案就是这个
//*[not(.//text())][not(ancestor::*[not(.//text())])]
第二个谓词从结果中删除所有已经包含在结果中的至少一个祖先的节点
答案 3 :(得分:0)
您还可以使用更简单易读的
//*[not(.//text())]
如果您愿意,可以<{>>或not(...)
替换empty(...)
。
两者都已经过优化,所以即使是简单的XPath实现也应该能够以“快速失败”的方式实现它们(找到一个文本节点,将谓词评估为false)。