Search code examples
xmlperl

How can I capture xml nodes into hash?


<?xml version="1.0" ?>
<Details date="2022-02-09" ver="1">
<VerNum>/14</VerNum>
<Info>
 <model>S22</model>
 <branch name="city_1">
  <stock>10000</stock>
  <def>1</def>
 </branch>
 <branch name="city_2">
  <stock>2000</stock>
  <def>2</def>
 </branch>
 <branch name="city_3">
  <stock>3000</stock>
  <def>0.3</def>
 </branch>
</Info>
</Details>

I was trying to access this sample xml file using the code below.

use strict;
use warnings;
use XML::LibXML;
my $xml = glob("/ThisPC/C:/ex.xml");
my $parser = XML::LibXML->load_xml(location=>$xml);
foreach my $sec ($parser->findnodes('/Details/Info')) { 
    my $model = $sec->findvalue('./model');
    my $branch = join '',map{$_ ->to_literal; } $sec->findnodes('./branch/@name');
print $branch;
    my $def = join '',map{$_ -> to_literal; } $sec->findnodes('./branch/def'); 
print "\n",$def;
    my $sto = join '',map{$_ -> to_literal ; } $sec -> findnodes('./branch/stock');
print "\n",$sto;
}

But I need to store results to hash instead of string. I don't understand how I can do it. Can anyone please help me/ guide me how I can do that please ??


Solution

  • Here's a demonstration that pulls out the branch information (Itself stored in a hash ref) and adds them all to a hash table:

    #!/usr/bin/env perl
    use warnings;
    use strict;
    use XML::LibXML;
    use Data::Dumper;
    
    # Use DATA instead of a separate file to keep the demo self-contained
    my $parser = XML::LibXML->load_xml({ IO => *DATA});
    
    # Iterate over each branch, extracting values from child nodes and
    # saving in a hash
    my %branches;
    for my $branch ($parser->findnodes('/Details/Info/branch')) {
        my $name = $branch->getAttribute('name');
        my $stock = $branch->findvalue('stock/text()');
        my $def = $branch->findvalue('def/text()');
        $branches{$name} = { stock => $stock, def => $def };
    }
    
    # And pretty-print the hash
    print Dumper(\%branches);
    
    __DATA__
    <?xml version="1.0" ?>
    <Details date="2022-02-09" ver="1">
    <VerNum>/14</VerNum>
    <Info>
     <model>S22</model>
     <branch name="city_1">
      <stock>10000</stock>
      <def>1</def>
     </branch>
     <branch name="city_2">
      <stock>2000</stock>
      <def>2</def>
     </branch>
     <branch name="city_3">
      <stock>3000</stock>
      <def>0.3</def>
     </branch>
    </Info>
    </Details>
    

    Output:

    $VAR1 = {
              'city_1' => {
                            'stock' => '10000',
                            'def' => '1'
                          },
              'city_3' => {
                            'stock' => '3000',
                            'def' => '0.3'
                          },
              'city_2' => {
                            'stock' => '2000',
                            'def' => '2'
                          }
            };
    

    You can then do whatever you need with that data structure. If you're not familiar with things like hashes of hashrefs in perl, start by reading perldsc.