Traverse YAML node tree with non-unique values

I have a YAML document which I believe is valid (at least it would be
representable in XML):

purchase_order:
  date: 10/12/2010
  vendor: 12345
  item:
    product: Tomatoes
    quantity: 5
  item:
    product: Eggs
    quantity: 2

The problem is that using YAML.read on this produces a Hash in which
only one item occurs because (naturally) it has to be unique.

How can one traverse the nodes in a YAML document like this?

···

--
Posted via http://www.ruby-forum.com/.

Append a number to the item entries, before loding via YAML.

···

--
Posted via http://www.ruby-forum.com/.

I have a YAML document which I believe is valid (at least it would be
representable in XML):

If Ruby can't read it, it's not valid. :wink: SCNR

purchase_order:
date: 10/12/2010
vendor: 12345
item:
product: Tomatoes
quantity: 5
item:
product: Eggs
quantity: 2

The problem is that using YAML.read on this produces a Hash in which
only one item occurs because (naturally) it has to be unique.

How can one traverse the nodes in a YAML document like this?

You could parse it like any ol' text file, and build your Hash by
hand, with anything ending in a colon being a Hash key, whereas
anything that appears multiple times become a nested Hash with the key
that would normally be overwritten becoming the key to the nested
hash, and the, in your example, product becomes the nested Hash's
keys.

Like so:

"purchase_order" => { "date" => "10/12/2010", "vendor" => "12345",
"item" => {"Eggs" => 2, "Tomatoes" => 5} }

···

On Mon, Dec 6, 2010 at 11:43 AM, Martin C. <mydoghasworms@gmail.com> wrote:

--
Phillip Gawlowski

Though the folk I have met,
(Ah, how soon!) they forget
When I've moved on to some other place,
There may be one or two,
When I've played and passed through,
Who'll remember my song or my face.

@Fritz: Thanks, however, I am not the one building the file, so I need
to process it as I get it. (This is just a simplification of course).

@Philip: Thanks for the suggestion, I was hoping there is an easier way.

I see the YAML library has a each_node method, so I was hoping there is
some alternative means to traverse the YAML nodes in the tree.

···

--
Posted via http://www.ruby-forum.com/.

Rather than having multiple keys that are the same (which doesn't work since
this is a hash data structure), you instead use an Array. I find an easier
way to figure out how things should look it is to go from data that you want
(what should it look like after being read), then dump it, and examine the
results.

data = {
  :purchase_order => {
    :date => '10/12/2010' ,
    :vendor => 12345,
    :items => [{
      :product => 'Tomatoes',
      :quantity => 5,
    },{
      :product => 'Eggs',
      :quantity => 2,
    }]
  }
}

require 'yaml'
result = YAML.dump(data)
puts result
puts

require 'pp'
pp YAML.load(result)

# >> ---
# >> :purchase_order:
# >> :date: 10/12/2010
# >> :vendor: 12345
# >> :items:
# >> - :product: Tomatoes
# >> :quantity: 5
# >> - :product: Eggs
# >> :quantity: 2
# >>
# >> {:purchase_order=>
# >> {:date=>"10/12/2010",
# >> :vendor=>12345,
# >> :items=>
# >> [{:product=>"Tomatoes", :quantity=>5}, {:product=>"Eggs",
:quantity=>2}]}}

···

On Mon, Dec 6, 2010 at 4:43 AM, Martin C. <mydoghasworms@gmail.com> wrote:

I have a YAML document which I believe is valid (at least it would be
representable in XML):

purchase_order:
date: 10/12/2010
vendor: 12345
item:
   product: Tomatoes
   quantity: 5
item:
   product: Eggs
   quantity: 2

The problem is that using YAML.read on this produces a Hash in which
only one item occurs because (naturally) it has to be unique.

How can one traverse the nodes in a YAML document like this?

--
Posted via http://www.ruby-forum.com/\.

Thanks Josh for the detailed reply. Looking at the YAML in your first
reply though, I have to wonder: You end up with duplicate keys under the
items node, and if you load that with YAML, won't you have the same
problem of only one product and one quantity remaining?

In any case, I am trying to cater for the situation where the creation
of the file is out of my control, i.e. I am receiving it from an
external source.

But thanks.

···

--
Posted via http://www.ruby-forum.com/.

Actually that document *is* invalid.
The YAML spec [1] says about mappings:
  The content of a mapping node is an unordered set of key: value node
  pairs, with the restriction that each of the keys is unique.

[1] - http://yaml.org/spec/1.2/spec.html#id2764044

···

On Mon, 2010-12-06 at 19:43 +0900, Martin C. wrote:

I have a YAML document which I believe is valid (at least it would be
representable in XML):

purchase_order:
  date: 10/12/2010
  vendor: 12345
  item:
    product: Tomatoes
    quantity: 5
  item:
    product: Eggs
    quantity: 2

The problem is that using YAML.read on this produces a Hash in which
only one item occurs because (naturally) it has to be unique.

How can one traverse the nodes in a YAML document like this?

Ah, thanks, and now I also see from Josh's YAML sample that it has
arrays with the leading '-'.

Sorry Josh! And thanks Niklas!

Case closed.

···

--
Posted via http://www.ruby-forum.com/.

Actually, the keys should be strings:

data = {
  'purchase_order' => {
    'date' => '10/12/2010' ,
    'vendor' => 12345,
    'items' => [{
      'product' => 'Tomatoes',
      'quantity' => 5,
    },{
      'product' => 'Eggs',
      'quantity' => 2,
    }]
  }
}

require 'yaml'
result = YAML.dump(data)
puts result
puts

require 'pp'
pp YAML.load(result)

···

On Mon, Dec 6, 2010 at 5:36 AM, Josh Cheek <josh.cheek@gmail.com> wrote:

data = {
  :purchase_order => {
    :date => '10/12/2010' ,
    :vendor => 12345,
    :items => [{
      :product => 'Tomatoes',
      :quantity => 5,
    },{
      :product => 'Eggs',
      :quantity => 2,
    }]
  }
}

If you use YAML.parse, you'll get a YAML::Syck::Map. You can traverse
that and build your hashes yourself. Use pp to get a picture of what's
inside.

···

On Mon, 2010-12-06 at 20:33 +0900, Martin C. wrote:

@Fritz: Thanks, however, I am not the one building the file, so I need
to process it as I get it. (This is just a simplification of course).

@Philip: Thanks for the suggestion, I was hoping there is an easier way.

I see the YAML library has a each_node method, so I was hoping there is
some alternative means to traverse the YAML nodes in the tree.

A key is the name you use to refer to that set of data. Perhaps you mean
that I end up with two items, but you will notice they are not accessed by
name. Each item is accessed by position rather than key, because it is an
Array rather than a Hash, so it does not have the clashing keys problem.

···

On Mon, Dec 6, 2010 at 5:52 AM, Martin C. <mydoghasworms@gmail.com> wrote:

Thanks Josh for the detailed reply. Looking at the YAML in your first
reply though, I have to wonder: You end up with duplicate keys under the
items node, and if you load that with YAML, won't you have the same
problem of only one product and one quantity remaining?