views:

320

answers:

3

Alright I have an xml document that looks something like this:

    <xml>
     <list>
      <partner>
       <name>Some Name</name>
       <status>active</status>
       <id>0</id>
      </partner>
      <partner>
       <name>Another Name</name>
       <status>active</status>
       <id>1</id>
      </partner>
    </list>
   </xml>

I am using ruby's lib-xml to parse it. I want to find if there is a partner with the name 'Some Name' in a quick and ruby idiomatic way.

How can I do this in one line or ruby code, assuming i have a the document parsed in a variable named document.. Such that i can call document.find(xpath) to retrieve nodes. I have had to do this multiple times in slightly different scenarios and now its starting to bug me.

I know i can do the following (but its ugly)

 found = false
 document.find('//partner/name').each do |name|
  if (name.content == 'Some Name')
   found = true
   break
  end
 end
 assert(found, "Some Name should have been found")

but i find this really ugly. I thought about using the enumeration include? mixin method but that still won't work because I need to get the .content field of each node as opposed to the actual node... While writing this, I though of this (but it seems somewhat inefficient albeit elegant)

found = document.find('//partner/name').collect{|name| name.content}.member?("Some Name")

Are there any other ways of doing this?

A: 

I would use a language that natively operates on XML (XQuery for example). With XQuery it is possible to formulate this sort of queries over xml data in a concise and elegant way.

lewap
+2  A: 

What about this?

found = document.find("//partner[name='Some Name']").empty?
Jose Basilio
+2  A: 

I tried this solution:

 found = document.find("//partner[name='Some Name']") != nil

but I got an error saying the xpath expression was invalid. However, i was reading some xpath documentation it it looks like you can call a text() function in the expression to get the text node. I tried the following and it appears to work:

 found = document.find("//partner/name/text()='Some Name'")

found actually is not a xml node but a true/false object so this works.

Matt Wolfe
That first XPath works for me with both libxml-ruby and Nokogiri, so I'm not sure why it gave you an invalid XPath error. One note is that `!= nil` may not do what you want it to - even in the event of no matches, you'll get a collection back. You probably want to use .empty? to check if anything was found.
Greg Campbell
@Greg. I agree with you. The xpath is works. Thanks for the tip on using .empty? instead of '!=nil'
Jose Basilio
I'm not sure what I had done wrong but I can in fact use this syntax now after trying again (maybe i had a / before name). Using .empty? though will need to be negated for the logic to work, thus:found = document.find("//partner[name='Some Name']").empty?should befound = !document.find("//partner[name='Some Name']").empty?
Matt Wolfe