Mike
Mike

Reputation: 1580

XML Parsing and converting to hash - Ruby

I'm using Ruby, Norkigiri and Nori. I would like some thoughts about how I should go about parsing this XML file.

In this schema, an entity can include multiple contacts.

I need to return a hash of the following:

I thought about using xpath to try return the preferred email contact.

entities = doc.xpath("/entity_list/entity").each do |entity|
   puts entity.xpath("contact_list/contact[contains(type,'Email') and contains(preferred, '1')]")
end



  <entity>
    <id>21925</id>
    <last_name>Smith</last_name>
    <first_name>John</first_name>
    <preferred_name>Johnny</preferred_name>
    <manager>Timmy</manager>
    <dob>1970-01-01</dob>
    <type>individual</type>
    <contact_list>
      <contact>
        <type>Mobile Phone</type>
        <preferred>0</preferred>
        <value>563478653478</value>
      </contact>
      <contact>
        <type>Pager</type>
        <preferred>0</preferred>
        <value>7354635345</value>
      </contact>
      <contact>
        <notes>None</notes>
        <type>Home Email</type>
        <preferred>1</preferred>
        <value>johhny@smith.com</value>
        <comments>None</comments>
      </contact>
      <contact>
        <notes>None</notes>
        <type>Work Email</type>
        <preferred>0</preferred>
        <value>johhny@gmail.com</value>
        <comments>None</comments>
      </contact>
      <contact>
        <type>Home Phone</type>
        <preferred>1</preferred>
        <value>56537646365</value>
      </contact>
     </contact_list>
     </entity>

What would be the best way to approach this problem?

Thanks

Upvotes: 0

Views: 197

Answers (1)

Jacob Brown
Jacob Brown

Reputation: 7561

Here is one way of doing it (off the top of my head, based on your initial solution):

entities = doc.xpath("/entity_list/entity").map do |entity|
  {
    :id => entity.at_xpath("id").content.to_i,
    :first_name => entity.at_xpath("first_name").content,
    :last_name => entity.at_xpath("last_name").content,
    :preferred_email => entity.at_xpath("contact_list/contact[contains(type,'Email') and contains(preferred, '1')]/value").content,
    :manager => entity.at_xpath("manager").content
  }
end

EDIT

To rescue from missing nodes you could use ActiveSupport's try method, or just tack a rescue nil onto the end of each line, e.g.:

:first_name => (entity.at_xpath("first_name").content rescue nil),

But it would be better to use a helper method, something like:

def get_node_content(entity, xpath)
  node = entity.send(:at_xpath, xpath)
  node ? node.content : nil
end

Then you could use it like:

:first_name => get_node_content(entity, "first_name"),

Upvotes: 1

Related Questions