use strict; use warnings; no warnings 'uninitialized'; use XML::Rules; my %written; my %depends; my $parser = XML::Rules->new( style => 'filter', rules => { _default => 'raw', 'name,members' => 'raw extended', 'Group' => 'raw extended array', record => sub { my @I_depend; if (exists $_[1]->{':members'} and exists $_[1]->{':members'}{':Group'}) { @I_depend = grep !exists $written{$_}, map $_->{_content}, @{$_[1]->{':members'}{':Group'}}; } if (@I_depend) { $_[1]->{':I_depend'} = {map {$_ => 1} @I_depend}; foreach (@I_depend) { push @{$depends{$_}}, $_[1] } return; } else { my $name = $_[1]->{':name'}{_content}; $written{$name} = 1; my @to_write = $_[1]; if (exists $depends{$name}) { push @to_write, find_dependent($name); } return 'record' => \@to_write; } } } ); sub find_dependent { my $name = shift; my @to_write; foreach my $parent (@{$depends{$name}}) { delete $parent->{':I_depend'}{$name}; if (! %{$parent->{':I_depend'}}) { # if it doesn't depend on anything more push @to_write, $parent; push @to_write, find_dependent($parent->{':name'}{_content}); } } delete $depends{$name}; return @to_write; } $parser->filter(\*DATA); if (%depends) { print STDERR "Unsatisfied dependencies! Some records depend on these unknown groups: ", join ", ", keys %depends; }