use warnings; use strict; use XML::Twig; my($filename, @attrib, $verbose, # ... and some more options ... ); # ... get options ... my(%cluster, %element, %attrib); { my $EMPTY = []; my %handler; for my $a (@attrib) { $attrib{$a} = 1; } $handler{"element"} = sub { my($t, $e) = @_; my $id = $e->first_child_trimmed_text("id"); length($id) or die "invalid input: element with no id"; exists($element{$id}) and die qq[invalid input: duplicate element id "$id"]; my(%new, $a, $ae); for $ae ($e->children("value")) { $attrib{$a = $ae->att("id")} and $new{$a} = $ae->text; } $element{$id} = \%new; $t->purge; 1; }; $handler{"cluster"} = sub { my($t, $e) = @_; my $id = $e->first_child_trimmed_text("id"); my %c; length($id) or die "invalid input: cluster without id"; exists($cluster{$id}) and die qq[invalid input: duplicate cluster id "$id"]; my $g = $e->first_child_trimmed_text("goodness"); length($g) and $c{"goodness"} = 0 + $g; my @m = map { $_->trimmed_text } $e->children("member"); $c{"members"} = @m ? \@m : $EMPTY; my @c = map { $_->trimmed_text } $e->children("child"); $c{"children"} = @c ? \@c : $EMPTY; $cluster{$id} = \%c; $t->purge; 1; }; my $twig = XML::Twig->new("twig_handlers", \%handler); $verbose and warn "starting to parse xml file"; $twig->parsefile($filename); $verbose and warn "finished parsing xml file"; my $root = $twig->root; } # ... and I omit the rest of the code again ...