Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

XML::Simple how to force hash generation for keys

34 views
Skip to first unread message

Wolfgang Thomas

unread,
Jun 12, 2008, 5:42:50 AM6/12/08
to
Hi,

I use XML::Simple to parse the following small XML file:
<test>
<firstElem>
<anything id="1" value1="v11" value2="v12"/>
</firstElem>
<secondElem>
<anything id="2" value1="v21" value2="v22"/>
<anything id="3" value1="v31" value2="v32"/>
</secondElem>
</test>

Perl-Scipt:
use strict;
use warnings;
use Data::Dumper;


my $database = eval {XMLin("test.xml", keyattr => ['id'])};
if ($@) {
die ("Cannot parse test.xml: $@\n");
}
print Dumper ($database);

XML::Simple generates the following data structure:
$VAR1 = {
'firstElem' => {
'anything' => {
'value1' => 'v11',
'id' => '1',
'value2' => 'v12'
}
},
'secondElem' => {
'anything' => {
'3' => {
'value1' => 'v31',
'value2' => 'v32'
},
'2' => {
'value1' => 'v21',
'value2' => 'v22'
}
}
}
};

Now I wonder why XMLin the hash-structure differs between 'firstElem'
and 'secondElem'. This makes parsing the datastructure (in my opinion)
unnecessary complex.
How can I force XMLin to generate a hash for id = '1', so that the
result would look like:
$VAR1 = {
'firstElem' => {
'anything' => {
'1' => {
'value1' => 'v11',
'value2' => 'v12'
},
}
},
'secondElem' => {
'anything' => {
'3' => {
'value1' => 'v31',
'value2' => 'v32'
},
'2' => {
'value1' => 'v21',
'value2' => 'v22'
}
}
}
};

I wonder whether I am doing something fundamentally wrong, as I have
looked into lots of FAQs and into the documentation of XML::Simple, but
could not figure out any option to generate the output the way I need it.

Kind regards
Wolfgang

Dan Rumney

unread,
Jun 12, 2008, 6:58:41 AM6/12/08
to
Wolfgang Thomas wrote:
[snip]

>
> Perl-Scipt:
> use strict;
> use warnings;
> use Data::Dumper;
>
>
> my $database = eval {XMLin("test.xml", keyattr => ['id'])};
> if ($@) {
> die ("Cannot parse test.xml: $@\n");
> }
> print Dumper ($database);

[snip]

What is XMLin?

This Perl script fails to run:

Cannot parse test.xml: Undefined subroutine &main::XMLin called at
newscript1.cgi line 6.

Andreas Pürzer

unread,
Jun 12, 2008, 8:52:08 AM6/12/08
to
Wolfgang Thomas schrieb:

> Hi,
>
> I use XML::Simple to parse the following small XML file:

[snip]

> How can I force XMLin to generate a hash for id = '1'

[more snippage]

> I wonder whether I am doing something fundamentally wrong, as I have
> looked into lots of FAQs and into the documentation of XML::Simple, but
> could not figure out any option to generate the output the way I need it.
>

You want the 'ForceArray' option:

#!/usr/bin/perl

use warnings;
use strict;

use Data::Dumper;
use XML::Simple;

my $xml = XMLin(
\*DATA,
ForceArray => ['anything'],
KeyAttr => ['id'],
);
print Dumper($xml);

__DATA__


<test>
<firstElem>
<anything id="1" value1="v11" value2="v12"/>
</firstElem>
<secondElem>
<anything id="2" value1="v21" value2="v22"/>
<anything id="3" value1="v31" value2="v32"/>
</secondElem>
</test>

> Kind regards
> Wolfgang

Greetings,
Andreas Pürzer

--
Have Fun,
and if you can't have fun,
have someone else's fun.
The Beautiful South

Wolfgang Thomas

unread,
Jun 12, 2008, 9:04:17 AM6/12/08
to
Oops, I forgot the most important use statement. Please add the
following line:
use XML::Simple;

Sorry for the inconvenience
Wolfgang

Wolfgang Thomas

unread,
Jun 12, 2008, 11:31:10 AM6/12/08
to Andreas Pürzer
Andreas Pürzer wrote:
> You want the 'ForceArray' option:
> ...

> my $xml = XMLin(
> \*DATA,
> ForceArray => ['anything'],
> KeyAttr => ['id'],

This generates exactly the output, that I expected. Thank you!

But honestly, I do not understand why: From the description of this
option I would expect that this option creates arrays, which I do not
want. But used, as you proposed, the option does not create arrays, but
the hash I was missing.

xho...@gmail.com

unread,
Jun 12, 2008, 12:20:25 PM6/12/08
to

KeyAttr controls how arrays are turned into hashes. But if there is no
array there, it won't be turned into a hash. So you have to force
single-element entries to be treated as an array of 1, so it can then be
detected and folded into a hash.

The docs are kind of written from the package creator's perspective rather
than the user's perspective. Unless you know that arrays are an
intermediate step between XML and final hash-based output, it is rather
confusing to have to think about arrays that are behind the scene which you
never see. (But on the other hand, the docs do tell you that you should
almost always have ForceArray on, and that having the default be for it to
be off was a mistake.)

Xho

--
-------------------- http://NewsReader.Com/ --------------------
The costs of publication of this article were defrayed in part by the
payment of page charges. This article must therefore be hereby marked
advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
this fact.

Wolfgang Thomas

unread,
Jun 17, 2008, 4:40:52 AM6/17/08
to
> The docs are kind of written from the package creator's perspective rather
> than the user's perspective. Unless you know that arrays are an
> intermediate step between XML and final hash-based output, it is rather
> confusing to have to think about arrays that are behind the scene which you
> never see. (But on the other hand, the docs do tell you that you should
> almost always have ForceArray on, and that having the default be for it to
> be off was a mistake.)

Xho, thanks for explaining the non-obvious aspects of the documentation.

0 new messages