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?

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

@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.

On Mon, Dec 6, 2010 at 11:43 AM, Martin C. [email protected]
wrote:

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

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} }


Phillip G.

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.

On Mon, Dec 6, 2010 at 4:43 AM, Martin C. [email protected]
wrote:

product: Eggs

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 5:36 AM, Josh C. [email protected] wrote:

  :quantity => 2,
}]

}
}

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)

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.

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.

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

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.

On Mon, Dec 6, 2010 at 5:52 AM, Martin C. [email protected]
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?

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.