XPath选择前面的元素与可选的插入空白文本节点
给定一个元素作为上下文我想选择前面的兄弟元素并检查它是否具有特定的名称。 需要注意的是,如果存在具有非空白内容的插入文本节点,我不想选择它。
例如,给定这个XML文档……
a1a2 b a3 a4 a5
…然后:
- 对于“a1”,应该没有匹配(紧接在它之前的
兄弟元素)
- 对于“a2”,则应匹配“a1”(没有插入的文本节点)
- 对于“a3”,应该没有匹配(存在具有非空白内容的插入文本节点)
- 对于“a4”,则应匹配“a3”(插入的文本节点仅为空格)
- 对于“a5”,应该没有匹配(前面的兄弟元素不是
)。
我可以检查前面的兄弟姐妹是否是 with
preceding-sibling::*[1][name()="a"]
但是,我无法弄清楚如何说“选择以下兄弟节点,无论元素或文本,看看是不是文本还是normalize-space(.)=""
。我最好的猜测是这样的:
preceding-sibling::*[1][name()="a"][following-sibling::node()[1][not(text()) or normalize-space(.)=""]]
……但似乎没有效果。
这是我的测试Ruby文件:
require 'nokogiri' xpath = 'preceding-sibling::*[1][name()="a"][following-sibling::node()[1][not(text()) or normalize-space(.)=""]]' fragment = Nokogiri::XML.fragment 'a1a2 b a3 a4 a5' fragment.css('a').each{ |a| p [a.text,a.xpath(xpath).to_s] } #=> ["a1", ""] #=> ["a2", ""] #=> ["a3", "a2"] #=> ["a4", "a3"] #=> ["a5", ""]
“a2”和“a3”的结果是错误的,让我感到困惑。 它正确地找到了前面的 ,但是没有正确地validation它的第一个后续兄弟是非文本(应该允许“a2”找到“a1”)还是只有空格(这应该是防止的)发现“a2”的“a3”。
编辑 :这是我写的XPath,以及我打算做的事情:
使用 :
/*/a/preceding-sibling::node() [not(self::text()[not(normalize-space())])] [1] [self::a]
基于XSLT的validation:
在提供的XML文档上应用此转换时:
a1a2 b a3 a4 a5
评估XPath表达式,并将此评估选择的节点复制到输出 :
a1 a3
更新 :
问题中的XPath表达式有什么问题?
问题出在这里 :
[not(text()) or normalize-space(.)='']
这将测试上下文节点是否没有文本节点子节点。
但是OP希望测试上下文节点是否是文本节点。
方案 :
将以上内容替换为 :
[not(self::text()) or normalize-space(.)='']
基于XSLT的validation :
现在,这种转换产生了完全想要的结果:
a1 a3