The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.
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>