Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

How do I correctly use arrays with XML::Simple?

by ccarden (Monk)
on Oct 08, 2003 at 15:29 UTC ( [id://297630]=perlquestion: print w/replies, xml ) Need Help??

ccarden has asked for the wisdom of the Perl Monks concerning the following question:

For my test, I have a simple XML structure:
<config> <wrapper name="testName 1.0.3" script="/usr/people/ltorvalds/apps/ +wrapper.pl" app="testApp.exe"> <envVar name="TMPDIR" value="/usr/tmp"/> <envVar name="APPDIR" value="/usr/bin"/> </wrapper> </config>
The following code successfully parses the xml file:
#!/usr/bin/perl -w use XML::Simple; my $ref = XMLin(); my $wrapName = "testName 1.0.3"; print "$ref->{wrapper}->{$wrapName}->{script}\n"; print "$ref->{wrapper}->{$wrapName}->{envVar}->{TMPDIR}->{value}\n";
... and correctly produces the following output ...
/usr/people/ltorvalds/wrapper.pl /usr/tmp
Now, if I try to treat the <envVar> tags as an array, I run into trouble:
print "$ref->{wrapper}->{$wrapName}->{envVar}->[0]->{value}\n";
... produces a blank line. I assumed that this was because I needed to turn forceArray on, so I changed the call to XMLin():
my $ref = XMLin(xmlTest.xml, forceArray=>['envVar']);
... but still I get the same blank line as output.

I suspect that I'm either using forceArray incorrectly or I'm using an invalid array reference. Any insight as to where my folly lies would be appreciated.

Update

Thanks for all of the input. What have I learned? I have learned that I need to:

  1. learn how to better use the debugger
  2. read the XML::Simple docs more carefully
  3. study up on hashes and arrays
It all pretty much boils down to rtfm, but I am grateful to all of you for the focused answers.

Replies are listed 'Best First'.
Re: How do I correctly use arrays with XML::Simple?
by mirod (Canon) on Oct 08, 2003 at 16:09 UTC

    You need to use the { elt => attribute } form of keyattr.

    From the docs:

    keyattr => { list } (in+out) (IMPORTANT!)
    This alternative (and preferred) method of specifiying the key attributes allows more fine grained control over which elements are folded and on which attributes. For example the option keyattr => { package => 'id' } will cause any package elements to be folded on the 'id' attribute. No other elements which have an 'id' attribute will be folded at all.

    So here is the code you want:

    #!/usr/bin/perl -w use strict; use XML::Simple; undef $/; my $ref = XMLin( <DATA>, forcearray => 1, keyattr => { wrapper => "nam +e" }); my $wrapName = "testName 1.0.3"; print "$ref->{wrapper}->{$wrapName}->{script}\n"; print "$ref->{wrapper}->{$wrapName}->{envVar}->[0]->{value}\n"; __DATA__ <config> <wrapper name="testName 1.0.3" script="/usr/people/ltorvalds/apps/ +wrapper.pl" app="testApp.exe"> <envVar name="TMPDIR" value="/usr/tmp"/> <envVar name="APPDIR" value="/usr/bin"/> </wrapper> </config>
Re: How do I correctly use arrays with XML::Simple?
by EdwardG (Vicar) on Oct 08, 2003 at 16:04 UTC

    Looking at this in the debugger it seems that XMLin() may not be giving you what you expected:

    c:\>perl -d test.pl Loading DB routines from perl5db.pl version 1.19 Editor support available. Enter h or `h h' for help, or `perldoc perldebug' for more help. main::(test.pl:6): my $ref = XMLin(<<XML main::(test.pl:7): <config> main::(test.pl:8): <wrapper name="testName 1.0.3" script="/us +r/people/ltorvalds/apps/wrapper.pl" app="testApp.exe"> main::(test.pl:9): <envVar name="TMPDIR" value="/usr/tmp" +/> main::(test.pl:10): <envVar name="APPDIR" value="/usr/bin" +/> main::(test.pl:11): </wrapper> main::(test.pl:12): </config> main::(test.pl:13): XML main::(test.pl:14): ); DB<1> n main::(test.pl:15): my $wrapName = "testName 1.0.3"; DB<1> x $ref 0 HASH(0x1cb36d0) 'wrapper' => HASH(0x1cc3a10) 'app' => 'testApp.exe' 'envVar' => HASH(0x1cf4b20) 'APPDIR' => HASH(0x1cf4be0) 'value' => '/usr/bin' 'TMPDIR' => HASH(0x1ce6d34) 'value' => '/usr/tmp' 'name' => 'testName 1.0.3' 'script' => '/usr/people/ltorvalds/apps/wrapper.pl' DB<2>

    No arrays there, just hashes.

Re: How do I correctly use arrays with XML::Simple?
by grantm (Parson) on Oct 08, 2003 at 18:16 UTC
    Any insight as to where my folly lies would be appreciated.

    You're trying to treat $ref->{wrapper}->{$wrapName}->{envVar} as a hashref in the first case and an arrayref in the second - it can't be both. If you need it to be both then you need XML::Smart :-)

    The reason it is a hashref is because you're not setting the KeyAttr option so its default value is causing the array of envVar element to be transformed into a hash keyed on the value of the 'name' parameter. If you don't want that, set KeyAttr => { }.

    Oh and the option names are case-insensitive as long you have the latest version of XML::Simple.

Re: How do I correctly use arrays with XML::Simple?
by eric256 (Parson) on Oct 08, 2003 at 15:52 UTC

    With XML::Simple alot of times its bes to use Data::Dumper and print out the hash it gives you. Also, i beleive that it is forcearray (all lowercase), even though the docs say its they way you have it.
    ___________
    Eric Hodges

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://297630]
Approved by vagnerr
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (3)
As of 2024-04-20 11:00 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found