Check if child node exists (without getting NoMethodError)

<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 a "Method missing" error. How can I check to avoid this error? What is a conditional expression that I would use?

+7
source share
2 answers

Technique 1: Rescue any mistake

 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 

Technique 2: Look before the jump (aka Do not Use Slop)

 %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 

When using slop, the code (no-slop) some_node.at_xpath("foo") is identical to some_node.foo , except that it returns nil when a child node with this name does not exist. Indeed, the Slop implementation simply calls xpath for the element name: if it finds many elements, you get this Nodeset; if he finds only one element, he gives you that; if it does not find elements, it raises the value of NoMethodError . 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 docs say about Slop (in footnotes):

Do not use this.
No, really, do not use this. If you use it, do not report errors.
You have been warned!

In general, XPath is much more efficient and faster than a workaround. For example, if you want to iterate over all <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 at the end, we can help you improve the code. In my personal opinion, Slop is usually a less efficient way to go through a document.

+7
source

Here is an easy way to do 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 
+3
source

All Articles