I have an xml that looks like this
<list>
<item>
<id>1</id>
<data>123</data>
</item>
<item>
<id>2</id>
<data>abc</data>
</item>
</list>
Is there any builtin function in nokogiri that allows me to get an <item>
that have an specific <id>
?
Something that would look like this:
require 'nokogiri'
xml = '
<list>
<item>
<id>1</id>
<data>123</data>
</item>
<item>
<id>2</id>
<data>abc</data>
</item>
</list>
'
data = Nokogiri::XML(xml)
item = data.xpath("//item:contains('id', '2')")
I could achieve it by item = data.xpath("//item").select {|d| d.xpath("id").text == "1"}
but is there any builtin way to achieve this?
`
CodePudding user response:
Following the comments I'll put it in the answer.
item = data.xpath("//id[text() = '2']/parent::node()")
This is a solution with xpath. Instead of iterating through items one can directly access what is needed. If I do a benchmark on this solution it shows 0.000068 compared to your approach item = data.xpath("//item").select {|d| d.xpath("id").text == "1"}
which scores 0.000121, basically a 2 times improvement.
As for Slop, it's a decorator that will make your code look more "builtin", native, whatever. First you'll need to change the way how you acquire data: data = Nokogiri::Slop(xml)
, Slop goes instead of XML. The code to achieve what you need will be:
item = data.list.item.select{|x| x.id.text == '2'}
As you see it lacks those xpath strings, utilizes ruby methods:
The Slop decorator implements method_missing such that methods may be used instead of CSS or XPath. source: w3cub
So, yeah, it looks cool