给定一个元素作为上下文,我想选择前面的同级元素并检查它是否具有特定名称。需要注意的是,如果存在包含非空白内容的中间文本节点,我不想选择它。
例如,给定这个 XML 文档...
<r>
<a>a1</a><a>a2</a>
b
<a>a3</a>
<a>a4</a>
<b/>
<a>a5</a>
</r>
…then:
- 对于“a1”应该没有匹配项(没有
<a>
紧邻其前面的兄弟元素)
- 对于“a2”,则应匹配“a1”(没有中间文本节点)
- 对于“a3”应该没有匹配项(中间有一个包含非空白内容的文本节点)
- 对于“a4”,则应匹配“a3”(中间的文本节点仅为空格)
- 对于“a5”,不应有匹配项(前面的同级元素不是
<a>
).
我可以检查前面的兄弟是否是<a>
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 '<a>a1</a><a>a2</a> b <a>a3</a> <a>a4</a> <b/> <a>a5</a>'
fragment.css('a').each{ |a| p [a.text,a.xpath(xpath).to_s] }
#=> ["a1", ""]
#=> ["a2", ""]
#=> ["a3", "<a>a2</a>"]
#=> ["a4", "<a>a3</a>"]
#=> ["a5", ""]
“a2”和“a3”的结果是错误的并且让我感到困惑。它找到前面的<a>
正确,但随后无法正确验证其第一个后续兄弟是否不是文本(这应该允许“a2”找到“a1”)或者它只是空白(这应该阻止“a3”找到“a2” ”。
Edit:这是我正在编写的 XPath,以及我想要它做什么: