in reply to XML plus Perl -- simply magic

(Regarding the article (also posted to the author with a little different wording).)
The code for the pet shop could be further shortened by using ForceArray => [dog, cat, hippo]. Not only would this make the structure returned by XMLin simpler, but it'd save the developer from having to unwrap the one item arrays. And would save some memory.

In case anyone is interested this is the implementation of the task (except for the ordering) using XML::Rules:

#!/usr/bin/perl -w use strict; use XML::Rules; use Date::Calc qw(Add_Delta_YM Decode_Date_EU Delta_Days Delta_YMD); u +se Data::Dumper; my @now = (localtime(time))[5, 4, 3]; $now[0] += 1900; # Perl years start in 1900 $now[1]++; # months are zero-based my $parser = XML::Rules->new( rules => [ price => sub { price => fixPrice( $_[1]->{_content}, 0.20 )}, dob => sub {age => dob2age( $_[1]->{_content})}, 'name,owner' => 'content', 'dog,cat,hippo' => sub {delete($_[1]->{_content}); $_[0] => $_[1]}, + ], style => 'filter', ); $parser->filterfile('pets.xml', \*STDOUT); # ... and the functions defined in the article
It's 67 lines and unlike the XML::Simple implementation works as a filter ... only the data of a single animal are in memory at any time.

With the ordering it's

#!/usr/bin/perl -w use strict; use XML::Rules; use Date::Calc qw(Add_Delta_YM Decode_Date_EU Delta_Days Delta_YMD); u +se Data::Dumper; my @now = (localtime(time))[5, 4, 3]; $now[0] += 1900; # Perl years start in 1900 $now[1]++; # months are zero-based my $parser = XML::Rules->new( rules => [ price => sub { price => fixPrice( $_[1]->{_content}, 0.20 )}, dob => sub {age => dob2age( $_[1]->{_content})}, 'name,owner' => 'content', '_default' => 'no content array', 'pets' => sub { my ($tag, $attrs) = @_; delete($attrs->{_content}); foreach my $kind (values %{$attrs}) { next unless ref($kind) eq 'ARRAY'; # just in case $kind = [sort {$a->{name} cmp $b->{name}} @$kind]; # sort the animals of a kind by name }; return $tag => $attrs; }, ], style => 'filter', ident => ' ', ); $parser->filterfile('pets.xml', \*STDOUT); # ... and the functions (78 lines in total)
though this of course can't work as a filter since it has to be able to sort everything. Whether that's clearer than the XML::Simple based code is a question :-)

P.S.: You need XML::Rules 0.17 for the identation to work.