Ruby XPath查找所有后续同级,直到下一个特定类型的同级
鉴于此XML/HTML:Ruby XPath查找所有后续同级,直到下一个特定类型的同级,ruby,xml,xpath,nokogiri,Ruby,Xml,Xpath,Nokogiri,鉴于此XML/HTML: Label1Value1 Label2Value2 Label3Value3aValue3b Label4Value4 我想找到所有的,然后,对于每个,找到下面的,直到下一个 使用Ruby,我可以这样完成: dl.xpath('dt')。每个都做| dt| ct=dt.xpath('count(后面的同级::dt')) dds=dt.xpath(“以下同级::dd[count(以下同级::dt)={ct}]” 放置“#{dt.text}:#{dds.map(&:te
Label1Value1
Label2Value2
Label3Value3aValue3b
Label4Value4
我想找到所有的
,然后,对于每个
,找到下面的
,直到下一个
使用Ruby,我可以这样完成:
dl.xpath('dt')。每个都做| dt|
ct=dt.xpath('count(后面的同级::dt'))
dds=dt.xpath(“以下同级::dd[count(以下同级::dt)={ct}]”
放置“#{dt.text}:#{dds.map(&:text.join(',')}”
结束
#=>标签1:Value1
#=>标签2:Value2
#=>标签3:Value3a,Value3b
#=>标签4:Value4
但是,正如您所看到的,我在Ruby中创建了一个变量,然后使用它编写了一个XPath。如何编写一个XPath表达式来实现相同的功能
我猜:
following-sibling::dd[count(following-sibling::dt)=count(self/following-sibling::dt)]
但显然我不明白self在那里的意思
此问题与类似,只是“停止”节点没有唯一标识符
这个问题与我的问题几乎相同,只是我要的是一个仅限XPath的解决方案。一个可能的解决方案:
dl.xpath('dt').each_with_index do |dt, i|
dds = dt.xpath("following-sibling::dd[not(../dt[#{i + 2}]) or " +
"following-sibling::dt[1]=../dt[#{i + 2}]]")
puts "#{dt.text}: #{dds.map(&:text).join(', ')}"
end
这依赖于dt
元素的值比较,并且当存在重复项时将失败。以下(复杂得多)表达式不依赖于唯一的dt
值:
following-sibling::dd[not(../dt[$n]) or
(following-sibling::dt[1] and count(following-sibling::dt[1]|../dt[$n])=1)]
注意:您使用
self
失败,因为您没有正确使用它作为轴(self:
)。另外,self
始终只包含上下文节点,因此它将引用表达式检查的每个dd
,而不是返回原始dt
这是一个有趣的问题。@lwburk的回答和评论中已经提到了大多数问题。我的回答可能比OP需要的更详细或更详细,只是为了让随机读者了解这个问题中隐藏的复杂性
XPath 1.0中与此问题相关的功能
在XPath中,每个步骤以及所选节点集中的每个节点都独立工作。这意味着
子轴之后使用父轴
轴(相反的情况,从子轴到父轴,在没有附加信息的情况下,不是唯一可恢复的)。在这种情况下,以前步骤中的信息将在以后的步骤中更精确地重新创建(而不是访问以前已知的信息)
不幸的是,在本例中,除了使用XPath变量(需要事先定义)之外,我无法想出任何其他解决方案来引用以前已知的节点
XPath指定引用变量的语法,但没有指定定义变量的语法,定义变量的方式取决于使用XPath的环境。实际上,由于该建议指出“用于计算子表达式的变量绑定始终与用于计算包含表达式的变量绑定相同”,因此您还可以声明XPath明确禁止在XPath表达式内定义变量
重新制定的问题
在您的问题中,当给定一个
时,问题是在切换上下文节点后,识别以下
元素或最初给定的节点。识别最初给定的
是至关重要的,因为对于要过滤的节点集中的每个节点,谓词表达式都以该节点作为上下文节点进行计算;因此,如果上下文发生变化后无法识别原始的
,那么就不能在谓词中引用原始的
。这同样适用于在给定
的兄弟元素之后的
元素
如果您使用的是变量,那么有人可能会争论:1)使用XPath变量语法和Nokogiri声明变量的特定方式,或2)使用Nokogiri扩展的XPath语法,允许您在XPath表达式中使用Ruby变量,两者之间是否存在重大差异。在这两种情况下,变量都是以特定于环境的方式定义的,只有当变量的定义也可用时,XPath的含义才是明确的。类似的情况可以在XSLT中看到,在某些情况下,您可以选择1)在使用XPath表达式之前使用
定义变量,或者2)使用current()
(在XPath表达式内部)这是XSLT扩展
使用nodeset变量和Kaysian方法求解
您可以选择当前
元素后面的所有
元素以及后面的同级::dd
(设置A)。此外,您还可以选择下一个
元素后面的所有
元素以及后面的同级::dt[1]/后面的同级::dd
(设置B)。现在,设置差异a\B
会留下实际需要的
元素(a
dds = $setA[count(.|$setB) != count($setB)]
dl.xpath('dd').each do |dd|
dt = dd.xpath("preceding-sibling::dt[1]")
## Insert new Ruby magic here ##
end