Traverse YAML node tree with non-unique values

M

Martin C.

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?
 
P

Phillip Gawlowski

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. ;) SCNR
purchase_order:
=A0date: 10/12/2010
=A0vendor: 12345
=A0item:
=A0 =A0product: Tomatoes
=A0 =A0quantity: 5
=A0item:
=A0 =A0product: Eggs
=A0 =A0quantity: 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" =3D> { "date" =3D> "10/12/2010", "vendor" =3D> "12345",
"item" =3D> {"Eggs" =3D> 2, "Tomatoes" =3D> 5} }

--=20
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.
 
M

Martin C.

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

Josh Cheek

[Note: parts of this message were removed to make it a legal post.]

data = {
:purchase_order => {
:date => '10/12/2010' ,
:vendor => 12345,
:items => [{
:product => 'Tomatoes',
:quantity => 5,
},{
:product => 'Eggs',
: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)
 
J

Josh Cheek

[Note: parts of this message were removed to make it a legal post.]

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?
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}]}}
 
M

Martin C.

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

Martin C.

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

Josh Cheek

[Note: parts of this message were removed to make it a legal post.]

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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,534
Members
45,008
Latest member
Rahul737

Latest Threads

Top