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

hi all

this is the file contents with set of tags (not xml file)
<CCCMAP> <COMPONENT> <COMP_NAME>ip</COMP_NAME> <CCC> <CCC_NAME>ip1</CCC_NAME> <TC> <TC_LOC>/tftpboot/tc1</TC_LOC> </TC> </CCC> <CCC_NAME>ip2</CCC_NAME> <TC> <TC_LOC>/tftpboot/tc1</TC_LOC> <TC_LOC>/tftpboot/tc3</TC_LOC> <TC_LOC>/tftpboot/tc4</TC_LOC> </TC> </CCC> </COMPONENT> <COMPONENT> <COMP_NAME>parser</COMP_NAME> <CCC> <CCC_NAME>p1</CCC_NAME> <TC> <TC_LOC>/tftpboot/tc1</TC_LOC> <TC_LOC>/tftpboot/tc2</TC_LOC> </TC> </CCC> <CCC_NAME>p2</CCC_NAME> <TC> <TC_LOC>/tftpboot/tc1</TC_LOC> </TC> </CCC> <CCC_NAME>p3</CCC_NAME> <TC> <TC_LOC>/tftpboot/tc1</TC_LOC> <TC_LOC>/tftpboot/tc2</TC_LOC> <TC_LOC>/tftpboot/tc3</TC_LOC> </TC> </CCC> </COMPONENT> </CCCMAP>

and this is my code to generate a hash from this file
open (FILE, "< $mapfile") or die ("Unable to read the file $mapfile"); while (my $str = <FILE>) { chomp($str); $comp = $1 if $str =~ m{<COMP_NAME>(.*?)</COMP_NAME>}; $cmd = $1 if $str =~ m{<CCC_NAME>(.*?)</CCC_NAME>}; $tc = $1 if $str =~ m{<TC_LOC>(.*?)</TC_LOC>}; if ($tc) { push @tc, $tc; } if ( ($str =~ m{</TC>}) ) { $hoh{$comp}{$cmd} = {@tc}; #push @{$hoh{$comp}{$cmd}}, { @tc }; next; } elsif ( ($str =~ m{</CCC>})||($str =~ m{</COMPONENT>}) ) { undef @tc; undef $tc; next; } else { next; } } # print Dumper \%hoh;
and this is the output hash i get from this code
$VAR1 = { 'ip' => { 'ip1' => { '/tftpboot/tc1' => '/tftpboot/tc1' }, ' +ip2' => { '/tftpboot/tc4' => '/tftpboot/tc4', '/tftpboot/tc1' => '/tf +tpboot/tc3' } }, 'parser' => { 'p2' => { '/tftpboot/tc1' => '/tftpboo +t/tc1' }, 'p3' => { '/tftpboot/tc3' => '/tftpboot/tc3', '/tftpboot/tc +1' => '/tftpboot/tc2' }, 'p1' => { '/tftpboot/tc2' => undef, '/tftpbo +ot/tc1' => '/tftpboot/tc2' } } };
there is minor error in my code which makes this hash improper
the hash has to be like this
$VAR1 = { 'ip' => { 'ip1' => { '/tftpboot/tc1' }, 'ip2' => { '/tftpboo +t/tc4', '/tftpboot/tc1', '/tftpboot/tc3' } }, 'parser' => { 'p2' => { + '/tftpboot/tc1' }, 'p3' => { '/tftpboot/tc3', '/tftpboot/tc1', '/tft +pboot/tc2' }, 'p1' => { '/tftpboot/tc1' => '/tftpboot/tc2' } } };

please help me to fix this problem
thanks
rsennat

Edit: g0n - added readmore tags

Replies are listed 'Best First'.
Re: error in my code
by davorg (Chancellor) on Nov 23, 2005 at 11:27 UTC

    You say that the file isn't XML, but it looks like well-formed XML to me. In which case the easiest way to get it into a hash would be to use XML::Simple.

    --
    <http://dave.org.uk>

    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg

Re: error in my code
by reasonablekeith (Deacon) on Nov 23, 2005 at 11:52 UTC
    Well as said above you really ought to parse this a pure xml.

    You also don't say what's wrong with the output, which makes is hard to guess what the correct out put should be.

    Anyway, if you're intent on hacking this, the following code give the output as described. Is this what you're after?

    (PS. Could you change the title to something more searchable like 'problem parsing xml into a hash?')

    while (my $str = <DATA>) { chomp($str); $comp = $1 if $str =~ m{<COMP_NAME>(.*?)</COMP_NAME>}; $cmd = $1 if $str =~ m{<CCC_NAME>(.*?)</CCC_NAME>}; if ($str =~ m{<TC_LOC>(.*?)</TC_LOC>}) { $hoh{$comp}{$cmd}{$1} = undef; } } print Dumper \%hoh; __OUTPUT__ $VAR1 = { 'ip' => { 'ip1' => { '/tftpboot/tc1' => undef }, 'ip2' => { '/tftpboot/tc3' => undef, '/tftpboot/tc4' => undef, '/tftpboot/tc1' => undef } }, 'parser' => { 'p2' => { '/tftpboot/tc1' => undef }, 'p3' => { '/tftpboot/tc2' => undef, '/tftpboot/tc3' => undef, '/tftpboot/tc1' => undef }, 'p1' => { '/tftpboot/tc2' => undef, '/tftpboot/tc1' => undef } } };
    ---
    my name's not Keith, and I'm not reasonable.
      thats almost the one what i expect.
      but please see this format,
      $VAR1 = { 'ip' => { 'ip1' => { '/tftpboot/tc1' }, 'ip2' => { '/tftpboot/tc3', '/tftpboot/tc4', '/tftpboot/tc1' } }, 'parser' => { 'p2' => { '/tftpboot/tc1' }, 'p3' => { '/tftpboot/tc2', '/tftpboot/tc3', '/tftpboot/tc1' }, 'p1' => { '/tftpboot/tc2', '/tftpboot/tc1' } } };
      thanks
        That's not a valid data structure. This is what [id://Perl Mouse] was saying. You've got an odd number of elements in your hash (under 'ip2' and 'p2', infact all of them except 'p1')

        UPDATE:

        Swapping part of the hash for an array gives you this... Is this any closer?

        while (my $str = <DATA>) { chomp($str); $comp = $1 if $str =~ m{<COMP_NAME>(.*?)</COMP_NAME>}; $cmd = $1 if $str =~ m{<CCC_NAME>(.*?)</CCC_NAME>}; if ($str =~ m{<TC_LOC>(.*?)</TC_LOC>}) { push(@{$hoh{$comp}{$cmd}}, $1); } } __OUTPUT__ $VAR1 = { 'ip' => { 'ip1' => [ '/tftpboot/tc1' ], 'ip2' => [ '/tftpboot/tc1', '/tftpboot/tc3', '/tftpboot/tc4' ] }, 'parser' => { 'p2' => [ '/tftpboot/tc1' ], 'p3' => [ '/tftpboot/tc1', '/tftpboot/tc2', '/tftpboot/tc3' ], 'p1' => [ '/tftpboot/tc1', '/tftpboot/tc2' ] } };
        ---
        my name's not Keith, and I'm not reasonable.
Re: error in my code
by Perl Mouse (Chaplain) on Nov 23, 2005 at 11:52 UTC
    The hash you'd like it to be isn't very well formed. Several of the leaf hashes contain an odd number of elements. Are you sure the leaves shouldn't be arrays?
    Perl --((8:>*