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

I can't seem to get XML:Simple to create a hash tree the same way for different data. If there are two entries in my tree then I get named hashes of named hashes. If the XML only has one entry then the structure changes. How do I force the same structure all the time? The Perl:
use strict; use Data::Dumper; #require XML::Simple;# qw(:strict); use XML::Simple;# qw(:strict); # # I've got two xml files. The 1st contains 1 project the 2nd contains +2. # I need XML::Simple to create the same data structure every time. # How do I do this? # # Creates $tree->{project}{name} equal to 'PlayGround'. # But I don't want that. # I want $tree->{project}{'PlayGround'}. # my $xmldata1=<<EOF; <?xml version="1.0"?> <main> <project name="PlayGround"> <state name="Development"> </state> <state name="Emergency"> </state> </project> </main> EOF &xml1($xmldata1); # # I like how this structure is created. # How do I get this structure all the time? # my $xmldata2=<<EOF; <?xml version="1.0"?> <main> <project name="PlayGround"> <state name="Development"> </state> <state name="Emergency"> </state> </project> <project name="GymClass"> <state name="Development"> </state> <state name="Emergency"> </state> </project> </main> EOF &xml1($xmldata2); # --------------- show xml data. sub xml1 { my $data=shift; print "data\n$data\n"; my $simple = XML::Simple->new( ); my $tree = $simple->XMLin( $data #,forcearray=>0,KeyAttr => [ ] # creates array for 2nd +file. #,forcearray=>0 # no affect #,forcearray=>0 # no affect #,forcearray=>0,KeyAttr => [ ],ValueAttr => { project => 'name' } #,VarAttr => 'name' # no affect #,ValueAttr => { project => 'name' } # no affect #,ValueAttr => [ 'name' ] # no affect #,KeyAttr => { project => "+name" } # no affect #,KeyAttr => { project => 'name' } # no affect #,ForceContent => 1 # no affect ); print "0", Dumper( $tree ); print "1", Dumper( $tree->{project}{name} ); # don't wan +t this. print "2", Dumper( $tree->{project}{'PlayGround'} ) ; # want this + all the time. print "-" x 79, "\n"; }
Results:
E:\bin\XML>xmlqna.pl data <?xml version="1.0"?> <main> <project name="PlayGround"> <state name="Development"> </state> <state name="Emergency"> </state> </project> </main> 0$VAR1 = { 'project' => { 'name' => 'PlayGround', 'state' => { 'Emergency' => {}, 'Development' => {} } } }; 1$VAR1 = 'PlayGround'; 2$VAR1 = undef; ---------------------------------------------------------------------- +--------- data <?xml version="1.0"?> <main> <project name="PlayGround"> <state name="Development"> </state> <state name="Emergency"> </state> </project> <project name="GymClass"> <state name="Development"> </state> <state name="Emergency"> </state> </project> </main> 0$VAR1 = { 'project' => { 'PlayGround' => { 'state' => { 'Emergency' => {}, 'Development' => {} } }, 'GymClass' => { 'state' => { 'Emergency' => {}, 'Development' => {} } } } }; 1$VAR1 = undef; 2$VAR1 = { 'state' => { 'Emergency' => {}, 'Development' => {} } }; ---------------------------------------------------------------------- +---------

Replies are listed 'Best First'.
Re: XML::Simple hash tree structure not consistent
by ferreira (Chaplain) on Mar 29, 2007 at 18:32 UTC
    I can't seem to get XML:Simple to create a hash tree the same way for different data. If there are two entries in my tree then I get named hashes of named hashes. If the XML only has one entry then the structure changes. How do I force the same structure all the time?

    That's pretty common in XML::Simple usage and the reason why there's ForceArray (see this section).

    XMLin($xml, ForceArray => [ qw(state project) ] );
    The names in ForceArray stand for those tags which should always be transformed into array refs, no matter if only one appears. It is all explained in the fine documentation, including this FAQ.
Re: XML::Simple hash tree structure not consistent
by osunderdog (Deacon) on Mar 29, 2007 at 18:32 UTC

    Well, part of the answer might be this:

    my $simple = XML::Simple->new( KeepRoot=>1, #I usually keep the root. KeyAttr=>[], #do not use attributes as h +ash keys ForceArray => 1 #force array wrapping to + keep order );

    But I'm not sure you can have you're cake and eat it too on the criteria that:

    print "2", Dumper( $tree->{project}{'PlayGround'} ) ; # want this + all the time.

    Anytime you want to reference something through the hash, you're giving up your ability to predictably order them.

    Also note that I put these attributes on the XML::Simple instantiation rather than on the XMLin call. I would recommend you put this XML::Simple instance in the main and pass a reference to it to the xml1 function.

    Hazah! I'm Employed!

      I already have code that will loop through $tree but in this case I don't care about the order. I just need to access the values within or see if any values exist.

      for example:
      $foundit=$tree->{'PlayGround'}{'Development'}{'somthingelse'}{'another +thing'};
      or
      $foundit=$tree->{project}{'PlayGround'}{state}{'Development'}{cluster} +{'somthingelse'}{server}{'anotherthing'};
        Does anyone know if this can be done with a different PM?
Re: XML::Simple hash tree structure not consistent
by philcrow (Priest) on Mar 29, 2007 at 18:34 UTC
    Did you try either ForceArray => 1, or
    ForceArray => ['keyname']
    In the later case the list could have many elements.

    Phil