<root>
<channel>
<one>example</one>
<two>example2</two>
</channel>
<channel>
<one>example</one>
</channel>
</root>
In the second node, I don't have a <two>
node. If I use this: root.channel.two
obviously I get the error "Method missing". How can I check to avoid this error? What is the conditional statement I would use?
require 'nokogiri'
d = Nokogiri.XML("<foo><bar /></foo>")
bad = d.root.bar #=> undefined method `bar' for #<...> (NoMethodError)
d.slop!
yay = d.root.bar #=> #<... name="bar">
bad = d.root.xxx #=> undefined method `xxx' for #<...> (NoMethodError)
yay = d.root.xxx rescue nil #=> nil
%w[ bar xxx ].each do |node_name|
if n = d.root.at_xpath(node_name)
puts "Yay! #{n}"
else
puts "No node named #{node_name}"
end
end
#=> Yay! <bar/>
#=> No node named xxx
The (no-slop) code some_node.at_xpath("foo")
is identical to some_node.foo
when using slop, except that it returns nil
when no child node with that name exists. Indeed, the implementation of Slop just calls xpath
for the element name: if it finds many elements, you get that Nodeset; if it finds only one element, it gives you that; if it finds no elements, it raises the NoMethodError
. The important bits look like this:
def method_missing( name )
list = xpath(name)
if list.empty?
super # NoMethodError unless someone else handles this
elsif list.length == 1
list.first # Since we only found one element, return that
else
list # ...otherwise return the whole list
end
end
Here's what the Nokogiri documents say about Slop (in the footnotes):
Don’t use this.
No, really, don’t use this. If you use it, don’t report bugs.
You’ve been warned!
In general, XPath is way more powerful and faster than slop traversal. For example, if you want to iterate over every <two>
node, you can do:
d.xpath('/root/channel/two').each do |two|
# This will only find nodes that exist
end
If you describe what you really need to do in the end, we can help you craft better code. In my personal opinion Slop is generally a less-effective way to traverse a document.
Here is a simple way of doing this:
xml = Nokogiri::XML(open("http://www.google.com/ig/api?weather=Auckland+New+Zealand"))
@current_conditions = xml.xpath("//current_conditions")
if @current_conditions.empty?
@display_weather = 0
else
@display_weather = 1
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With