我正在尝试从下面的xml中获取一些节点。
<SalesStart Value="1412899200">10.10.2014</SalesStart>
<SalesEnd Value="4102358400">31.12.2099</SalesEnd>
<Price Value="4.9900">4,99</Price>
<SalesStartEst Value="1411516800">24.09.2014</SalesStartEst>
<SalesEndEst Value="1697500800">17.10.2023</SalesEndEst>
我可以访问doc.text_at('SalesStart')
之类的节点。是否可以访问具有正则表达式的节点,如
doc.text_at('Sales'[/Start/]) or doc.css('Sales'[/Start/])
这样我就可以在一个查询中得到2个节点**(SalesStart和SalesStartEst)**?
答案 0 :(得分:0)
你cannot use a generic regular expression in Nokogiri本身 - 因为它倾向于只支持XPath 1.0的libxml2 - 但在你的情况下你只需要名称以SalesStart
开头的元素。在XPath 1.0中可以使用starts-with()
函数:
# Find all elements, ensuring the correct prefix on the name
doc.xpath("//*[starts-with(name(),'SalesStart')]")
演示:
require 'nokogiri'
doc = Nokogiri.XML '
<r>
<SalesStart Value="1412899200">10.10.2014</SalesStart>
<SalesEnd Value="4102358400">31.12.2099</SalesEnd>
<Price Value="4.9900">4,99</Price>
<SalesStartEst Value="1411516800">24.09.2014</SalesStartEst>
<SalesEndEst Value="1697500800">17.10.2023</SalesEndEst>
</r>
'
starts = doc.xpath("//*[starts-with(name(),'SalesStart')]").map(&:text)
p starts #=> ["10.10.2014", "24.09.2014"]
但是,如果您需要正则表达式,那么您可以使用Nokogiri过度查找元素,然后使用Ruby来削减该集合。例如:
# memory-heavy approach; pulls all elements and then pares them down
starts = doc.xpath('//*').select{ |e| e.name =~ /^SalesStart/ }
# lightweight approach, accessing one node at a time
starts = []
doc.traverse do |node|
starts<<node if node.element? && node.name =~ /^SalesStart/
end
p starts.map(&:text) #=> ["10.10.2014", "24.09.2014"]
您甚至可以将其作为一种便利方法进行包装:
# monkeypatching time!
class Nokogiri::XML::Node
def elements_with_name_matching( regex )
[].tap{ |result| traverse{ |n| result<<n if n.element? && n.name=~regex } }
end
end
p doc.elements_with_name_matching( /^SalesStart/ ).map(&:text)
#=> ["10.10.2014", "24.09.2014"]