use strict; use warnings; no warnings 'uninitialized'; use XML::Rules; my %written; my %depends; my $parser = XML::Rules->new( style => 'filter', ident => "\t", stripspaces => 2, rules => { _default => 'as array', 'Group' => 'content array', 'name,comments,members' => 'as is', record => sub { #use Data::Dumper; #print Dumper($_[1]); my @I_depend; if (exists $_[1]->{members} and exists $_[1]->{members}{Group}) { @I_depend = grep !exists $written{$_}, @{$_[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, write it after this one push @to_write, $parent; push @to_write, find_dependent($parent->{name}{_content}); } } delete $depends{$name}; return @to_write; } $parser->filterfile('c:\temp\Groups.xml'); use Data::Dumper; if (%depends) { print STDERR "\nUnsatisfied dependencies!\n"; foreach my $missing (keys %depends) { print STDERR "Missing group '$missing' is a member of:\n"; print STDERR "BUT IT WAS WRITTEN!!\n" if (exists $written{$missing}) foreach my $failed (@{$depends{$missing}}) { print STDERR Dumper($failed); print STDERR " $failed->{':name'}{_content}\n"; } } } # ' " __DATA__ <SystemXchange version="1.0"> <summary> <tool version="2.8 build: [070207]">Enterprise Migration Tool</tool> <source></source> <comments> </comments> <timestamp>May 30, 2008 @ 10:00:00 CDT</timestamp> </summary> <!--Begin Group Records--> <records type="group" operation="insert"> <record> <name>GOLF</name> <comments> </comments> <departments> <department>Default</department> </departments> <members> <Group>ECHO</Group> <Group>BETA</Group> <Group>DELTA</Group> <Group>FOXTROT</Group> <Destination>bj1234</Destination> </members> <ta_properties> <FullName> </FullName> </ta_properties> </record> <record> <name>ECHO</name> <comments> </comments> <departments> <department>Default</department> </departments> <members> <Group>CHARLIE</Group> <Group>DELTA</Group> <Destination>cn1234</Destination> <Destination>mc1234</Destination> </members> <ta_properties> <FullName> </FullName> </ta_properties> </record> <record> <name>CHARLIE</name> <comments> </comments> <departments> <department>Default</department> </departments> <members> <Group>ALPHA</Group> <Group>DELTA</Group> <Destination>zt1234</Destination> <Destination>rx1234</Destination> </members> <ta_properties> <FullName> </FullName> </ta_properties> </record> <record> <name>BETA</name> <comments> </comments> <departments> <department>Default</department> </departments> <members> <Destination>bp1234</Destination> <Destination>cm1234</Destination> <Group>FOXTROT</Group> <Group>CHARLIE</Group> </members> <ta_properties> <FullName> </FullName> </ta_properties> </record> <record> <name>FOXTROT</name> <comments> </comments> <departments> <department>Default</department> </departments> <members> <Group>ALPHA</Group> <Destination>cn1234</Destination> <Destination>sc1234</Destination> <Destination>sp1234</Destination> </members> <ta_properties> <FullName> </FullName> </ta_properties> </record> <record> <name>DELTA</name> <comments> </comments> <departments> <department>Default</department> </departments> <members> <Group>ALPHA</Group> <Group>FOXTROT</Group> </members> <ta_properties> <FullName> </FullName> </ta_properties> </record> <record> <name>ALPHA</name> <comments> </comments> <departments> <department>Default</department> </departments> <members> <Destination>sm1234</Destination> </members> <ta_properties> <FullName> </FullName> </ta_properties> </record> </records> </SystemXchange>