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

Hi,

I'm a Perl newbie. I have the following in myfile.xml

<detail> <start> <nonterminal name="A" /> </start> <rules> <rule name="A" type="text"> <nonterminal name="AA" /> <nonterminal name="AC" /> <nonterminal name="AD" /> <nonterminal name="AB" /> <nonterminal name="AE" /> </rule> <rule name="AA" type="numeric"> <token>1</token> <token>10</token> </rule> <rule name="AC" type="alpanumeric"> <token>3</token> <nonterminal name="BE" /> <nonterminal name="CE" /> <token>30</token> </rule> <rule name="CE" type="special"> <token>var1</token> <token>var2</token> </rule> <rule name="BE" type="symbol"> <token>%</token> <token>#</token> </rule> </rules> </detail>

My program to read the above:

use XML::Simple; use Data::Dumper; my $file_name = "myfile.xml"; my $xmlObj = XML::Simple->new(); my $data = $xmlObj->XMLin($file_name); my $primitive = 'A' foreach my $mydata(keys %{$data->{rules}{rule}{$primitive}{nontermin +al}}) { print $mydata; print " "; }

The output I got is AC AA AE AB AD but I wanted it in its original position, ie, AA AC AD AB AE
and how would I print a mix of nonterminal and token (as in rule AC)?
Please help.

Replies are listed 'Best First'.
Re: XML::Simple How to print data in its original position
by tobyink (Canon) on Aug 02, 2012 at 14:09 UTC

    Set the KeyAttr option for <nonterminal> to the empty list.

    See XML::Simple for further details.

    Update: quick explanation for my rather terse answer... when elements are repeated, XML::Simple puts them into either a hash or an array. It chooses a hash if it can find an attribute to use as the hash key. By default the attributes id, key and name are used. Perl hashes don't preserve order; Perl arrays do. By setting the key attribute list to the empty list, you force XML::Simple to use arrays.

    That having all been said, in my experience for any even vaguely complex tasks, XML::Simple's "simplicity" actually ends up making things much harder. Witness the XML::LibXML solution...

    use 5.010; use XML::LibXML 1.94; use PerlX::MethodCallWithBlock; XML::LibXML:: -> load_xml(location => 'myfile.xml') -> findnodes("//nonterminal | //token") -> map { $_->{name} || $_->textContent } -> foreach { say }
    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
Re: XML::Simple How to print data in its original position
by Athanasius (Archbishop) on Aug 02, 2012 at 15:20 UTC

    Hello, Z_S, and welcome to the Monastery!

    Following the hints from daxim (since deleted) and tobyink (although I can’t find a solution that sets just the <nonterminal> KeyAttr option to the empty list), I came up with the following:

    #! perl use strict; use warnings; use XML::Simple; my $xml = do { local $/; <DATA> }; my $xmlObj = XML::Simple->new(); my $data = $xmlObj->XMLin($xml, KeyAttr => []); my (@a_out, @ac_out); foreach my $rule ( @{ $data->{rules}{rule} } ) { if ($rule->{name} eq 'A') { push @a_out, $_->{name} for @{ $rule->{nonterminal} }; } elsif ($rule->{name} eq 'AC') { push @ac_out, $_->{name} for @{ $rule->{nonterminal} }; push @ac_out, $_ for @{ $rule->{token} }; } } print join(' ', @a_out ), "\n"; print join(' ', @ac_out), "\n"; __DATA__ <detail> <start> <nonterminal name="A" /> </start> <rules> <rule name="A" type="text"> <nonterminal name="AA" /> <nonterminal name="AC" /> <nonterminal name="AD" /> <nonterminal name="AB" /> <nonterminal name="AE" /> </rule> <rule name="AA" type="numeric"> <token>1</token> <token>10</token> </rule> <rule name="AC" type="alpanumeric"> <token>3</token> <nonterminal name="BE" /> <nonterminal name="CE" /> <token>30</token> </rule> <rule name="CE" type="special"> <token>var1</token> <token>var2</token> </rule> <rule name="BE" type="symbol"> <token>%</token> <token>#</token> </rule> </rules> </detail>

    Output:

    AA AC AD AB AE BE CE 3 30

    I can’t see any way of retaining the interleaved ordering of rule AC’s <nonterminal> and <token> tags, though.

    HTH,

    Athanasius <°(((><contra mundum

Re: XML::Simple How to print data in its original position
by daxim (Curate) on Aug 02, 2012 at 13:35 UTC
    was wrong, deleted