查找名称与模式匹配的元素

时间:2015-01-23 08:38:14

标签: ruby regex nokogiri

我正在尝试从下面的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)**?

1 个答案:

答案 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"]