in reply to Re^2: Parsing XML w/ Attributes
in thread Parsing XML w/ Attributes

I would encourage you to use ForceArray. Even if it's not necessary here, down the road you'll almost certainly be glad you started out using it. This is how I would go about what you're doing, using ForceArray.
#!/usr/bin/perl -w use strict; use XML::Simple; my $parser = new XML::Simple(ForceArray => 1); my $ref = $parser->XMLin('c:\temp\file.xml'); foreach my $host (keys(%$ref)){ foreach my $proc (keys(%{$ref->{$host}[0]->{process}})){ print "$proc is running on $host\n"; } }

Replies are listed 'Best First'.
Re^4: Parsing XML w/ Attributes
by Jenda (Abbot) on Dec 20, 2007 at 00:46 UTC

    I think it's safe to assume each host is there just once so it may be better to use ForceArray => ['process'] Which will somewhat simplify the code:

    #!/usr/bin/perl -w use strict; use XML::Simple; my $parser = new XML::Simple(ForceArray => ['process']); my $ref = $parser->XMLin('c:\temp\file.xml'); foreach my $host (keys(%$ref)){ foreach my $proc (keys(%{$ref->{$host}->{process}})){ print "$proc is running on $host\n"; } }
    Also it may be better to use each() instead of foreach():
    #!/usr/bin/perl -w use strict; use XML::Simple; my $parser = new XML::Simple(ForceArray => ['process']); my $ref = $parser->XMLin('c:\temp\file.xml'); while (my ($host, $processes) = each %$ref){ foreach my $proc (keys(%{$processes->{process}})){ print "$proc is running on $host\n"; } }
    Or using a different module:
    use XML::Rules; my $parser = XML::Rules->new( rules => { process => sub { '@list' => $_[1]->{name}}, _default => sub { $_[0] => $_[1]->{list}}, config => 'pass no content', } ); my $data = $parser->parse(\*DATA); #use Data::Dumper; #print Dumper($data); foreach my $host (sort keys %$data) { foreach my $proc (@{$data->{$host}}) { print "$host runs $proc\n"; } } __DATA__ <?xml version="1.0" encoding="utf-8"?> <config> ...
      Good suggestion (++) on ForceArray => ['process']. I'm not quite sure I see the benefit of each() over foreach() though. Is it the syntax that you like better, or is there an inherit benefit that I'm not aware of?

        It's the fact that you can name both the key and the value from the hash as you iterate so you do not have to use $hash{$key}, but instead have just $value. Which is especially handy if that hash is not in a variable, but rather is part of a more complex datstructure. So that instead of

        foreach my $key (keys %{$data->{blah}[$idx]{blih}}) { print "$key : $data->{blah}[$idx]{blih}{$key}\n"; }
        you have just
        while (my ($key, $value) = each %{$data->{blah}[$idx]{blih}}) { print "$key : $value\n"; }

        In that example it did not make a big difference especially because the value was used only once, but it may be handy. Especially if you find yourself doing something like

        foreach my $key (keys %{$data->{blah}[$idx]{blih}}) { my $value = $data->{blah}[$idx]{blih}{$key}; ... }
        Of course you have to keep in mind that the two are not equivalent. The $value created in the last snippet is a copy, the $value created by each() is an alias. Which makes a huge difference if you modify it :-)