http://www.perlmonks.org?node_id=924612

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

dear monks,

I got a XML looking like this:
<opt> <parmsets name="EXAMPLE2"> <local name="loc1" value="none" /> <local name="loc2" value="none" /> <local name="loc3" value="none" /> <local name="loc4" value="none" /> <local name="loc5" value="none" /> <local name="loc6" value="none" /> <regional name="region1" value="none" /> <regional name="region2" value="none" /> <regional name="region3" value="none" /> <regional name="region4" value="none" /> </parmsets> <parmsets name="EXAMPLE1"> <local name="loc1" value="none" /> <local name="loc2" value="none" /> <local name="loc3" value="none" /> <local name="loc4" value="none" /> <local name="loc5" value="none" /> <local name="loc6" value="none" /> <regional name="region1" value="none" /> <regional name="region2" value="none" /> <regional name="region3" value="none" /> <regional name="region4" value="none" /> </parmsets> </opt>
now if i read it with xmlin i get
$VAR1 = { 'parmsets' => { 'EXAMPLE2' => { 'regional' => { 'region1' => { 'valu +e' => 'none' }, [..] }, 'local' => { 'loc2' => { 'value' => +'none' [...] } } }, 'EXAMPLE1' => { 'regional' => { 'region1' => {[... +]
keys of parmsets are "example1" and "example2".
but now: if i delete "EXAMPLE1" i get this:
$VAR1 = { 'parmsets' => { 'regional' => { 'region1' => { 'value' => 'none' }, 'region4' => { 'value' => 'none' }, 'region2' => { 'value' => 'none' }, 'region3' => { 'value' => 'none' } }, 'name' => 'EXAMPLE2', 'local' => { 'loc2' => { 'value' => 'none' }, 'loc6' => { 'value' => 'none' }, 'loc5' => { 'value' => 'none' }, 'loc4' => { 'value' => 'none' }, 'loc1' => { 'value' => 'none' }, 'loc3' => { 'value' => 'none' } } } };
the structure changed! now the keys of parmsets are "regional", "local" and "name".

how can i fix that **** ;-) ?


$perlig =~ s/pec/cep/g if 'errors expected';

Replies are listed 'Best First'.
Re: XML::Simple => XMLout()
by suaveant (Parson) on Sep 07, 2011 at 15:45 UTC
    XML::Simple has lots of options to change how it processes, I think the one you want is ForceArray

                    - Ant
                    - Some of my best work - (1 2 3)

Re: XML::Simple => XMLout()
by Jenda (Abbot) on Sep 08, 2011 at 09:22 UTC

    XML::Simple tends to guess how to simplify the data structure and produces inconsistent structures for tags that are sometimes repeated and sometimes occur just once. Or tags that sometimes have content and attributes and sometimes just the content.

    It's better to specify explicitly what and how do you want to keep from the tags. See Simpler than XML::Simple.

    use strict; use XML::Rules; my $parser = XML::Rules->new( stripspaces => 7, rules => { local => sub { '%local' => {$_[1]->{name} => $_[1]->{value}} } +, regional => sub { '%regional' => {$_[1]->{name} => $_[1]->{val +ue}} }, parmsets => 'by name', opt => 'pass', } ); use Data::Dumper; my $data = $parser->parse(\*DATA); print Dumper($data); __DATA__ <opt> <parmsets name="EXAMPLE2"> ...

    Jenda
    Enoch was right!
    Enjoy the last years of Rome.

Re: XML::Simple => XMLout()
by Khen1950fx (Canon) on Sep 07, 2011 at 17:03 UTC
    The XML wasn't valid, so I made a change at the start. Change <opt> to <opt/>. <opt> results in a premature end of data. Next, you'll need to use:
    my $config = XMLin($foo, KeyAttr => 1, ForceArray => 1);
    ForceArray by itself isn't enough. Here's what I got:
    #!/usr/bin/perl use strict; use warnings; use XML::Simple qw(:strict); my $foo = '/root/Desktop/log.xml'; my $config = XMLin($foo, KeyAttr => 1, ForceArray => 1); use Data::Dumper::Concise; print Dumper($config);

      The first line of the XML data was <opt> and the last line of the XML data was </opt>.

      That looks like a valid matching pair of opening and closing tags to me. Not sure I follow why you're suggesting that the OP to change <opt> to <opt/>, which in my opinion would leave an orphaned </opt> tag at the end.

      Am I missing something?

        You're not missing something. I have to agree with you. To get it to work with XMLin though, that's what I had to do. I originally put the xml under __DATA__: I had to use <opt/> for that; however, I just noticed that when I call the xml as a file, then <opt> works as it should. Sorry for the confusion.