1

I process several XML files by calling recursive method process_node:

    for my $file (@ARGV) {
            my $doc = XML::LibXML->load_xml(location => $file);

            my $report;
            my $items = [];

            process_node($doc->getDocumentElement, $report, $items);

            print Dumper($items);
    }

They all have similar structure:

  • A big parent node named CalRunnerReport with attributes BSN, ProjectName, StationName
  • And many children nodes named TestItem

I'm trying to prepare a array of hashes referenced by the variable $items- to be used as data source for DataTables.net (an HTML table component):

sub process_node($$$) {
        my ($node, $report, $items) = @_;

        return unless $node->nodeType == XML_ELEMENT_NODE;

        if ($node->nodeName eq 'CalRunnerReport') {
                my $attr = get_attributes($node);
                $report = {
                        BSN         => $attr->{BSN},
                        ProjectName => $attr->{ProjectName},
                        StationName => $attr->{StationName},
                }
        } elsif ($node->nodeName eq 'TestItem') {
                my $attr = get_attributes($node);
                push @$items, [      # XXX fails to create a hash
                        %$report,
                        %$attr,
                ];
        }

        for my $child ($node->getChildnodes) {
                process_node($child, $report, $items);
        }
}

sub get_attributes($) {
        my $node = shift;
        my $attr = {};

        for my $a ($node->attributes) {
                my $key = $a->name;
                my $val = $a->value;
                $attr->{$key} = $val;
        }

        return $attr;
}

However in the Data:Dumper output I see that the push statement above hasn't created a hash, but a list:

      [
        'BSN',
        '1147386447',
        'ProjectName',
        'R089',
        'StationName',
        'B',
        'ExecutionTime',
        '00:00:00',
        'Result',
        'PASS',
        'EndTime',
        '03/09/2013 21:00:03',
        'StartTime',
        '03/09/2013 21:00:03',
        'Name',
        'RecordOperationParameter'
      ],
      [
        'BSN',
        '1147386447',
        'ProjectName',
        'R089',
        'StationName',
        'B',
        'ExecutionTime',
        '00:00:00',
        'Result',
        'PASS',
        'EndTime',
        '03/09/2013 21:00:03',
        'StartTime',
        '03/09/2013 21:00:03',
        'Name',
        'ClearLimitTestPendingList'
      ]

Is there please a nice way to combine the 2 hashes %$report and %$attr to a single hash - without looping through all their keys?

Alexander Farber
  • 21,519
  • 75
  • 241
  • 416
  • Could you make it clear what data structure you were expecting? – amon Sep 05 '13 at 12:22
  • No, it's impossible. You will have to loop through the keys. The best solution is `{ %$report, %$attr }` unless you want to check if a value in `%$attr` will overwrite a value in `%$report`. – ikegami Sep 05 '13 at 13:19

1 Answers1

4

You want something like this:

push @$items, { %$report, %$attr };

Order matters - in this case, any shared keys will have the value from $attr rather than the value from $report in the result hash.

Mark Reed
  • 91,912
  • 16
  • 138
  • 175
  • Thanks, that was it! I've got confused and used wrong brackets in my `push` code – Alexander Farber Sep 05 '13 at 12:23
  • 1
    Yes, `[`...`]` brackets create a reference to an array, while `{`...`}` brackets create a reference to a hash. The value inside is just a list (in the case of a hash, that list consists of key1, value1, key2, value2,...), and can go either way. – Mark Reed Sep 05 '13 at 12:27