user1137277
user1137277

Reputation: 233

Using nokogiri to parse XML and create records with multiple attributes

Feels like I'm missing something pretty obvious here but can't see it.

I have an XML file and are using the Nokogiri gem.

The XML looks like this (imagine if you will an infinite amount of 'variants'):

<?xml version="1.0" encoding="UTF-8"?> 
<products> 
    <variant> 
        <sku type="string">123abc</sku>
        <inventory-quantity type="integer">68</inventory-quantity> 
    </variant> 
    <variant> 
        <sku type="string">321cba</sku>
        <inventory-quantity type="integer">22</inventory-quantity> 
    </variant>
</products>

I want to loop over the variants and create a corresponding record for each that contains the 'sku' and 'inventory-quantity' attributes.

This is what I've got so far, but instead of creating individual records, in the above case it creates two records and inserts the complete array or NodeSet that Nokogiri returns into each records attribute. So this:

doc = Nokogiri::XML(File.open("#{Rails.root}/public/new.xml")) 

variant = doc.xpath("//variant")

variant.each do |product| 

  sku = product.xpath("//sku").text
  quan = product.xpath("//inventory-quantity").text

  Productmapping.create(:sku => sku, :product_quantity => quan)

end

creates this...

sku              inventory-quantity

123abc321cba     6822
123abc321cba     6822

Where I actually want:

sku              inventory-quantity

123ab            68
321cba           22

It looks like it's because the xpath locator returns all occurrences into an array and I'm calling that array and inserting it for each record.

Thanks!

Upvotes: 3

Views: 6061

Answers (2)

bender
bender

Reputation: 1428

The answer is simple - instead of:

sku = product.xpath("//sku").text
quan = product.xpath("//inventory-quantity").text

just use:

sku = product.xpath("sku").text
quan = product.xpath("inventory-quantity").text

It's because //sku selects all the sku descendants of the document root.

Upvotes: 14

tiktak
tiktak

Reputation: 1811

Smth like:

doc = Nokogiri::XML(File.open("#{Rails.root}/public/new.xml"))  

variant = doc.xpath("//variant")

sku, quan = nil, nil
variant.each do |product| 


  product.children.each do |child|
      case child.name
       when 'sku'  
          sku = child.text
       when 'inventory-quantity'
          quan = child.text
       end
    end

  Productmapping.create(:sku => sku, :product_quantity => quan)

end

Or more magic and not beautiful but compact way:

sku = product.children[1].text
quan = product.children[3].text

Upvotes: 1

Related Questions