Added Orbit tools support.
#!perl -w
use strict;
use XML::Parser;
my $sysModel = shift or die "First arg must be system model xml file";
my @filters = @ARGV or die "Subsequent arg(s) must be filter(s) to apply";
# Sort out the positive and negative filters specified
my @negativeFilters;
my @positiveFilters;
foreach my $filter (@filters)
{
if ($filter =~ m{^!(.*)})
{
push @negativeFilters, $1;
}
else
{
push @positiveFilters, $filter;
}
}
# Read input tree
my $parser = new XML::Parser(Style => "Objects") or die;
my $sysTree = eval { $parser->parsefile($sysModel) } or die "Failed to parse $sysModel : $@";
# Apply filter
filterTree($sysTree->[0], \@negativeFilters, \@positiveFilters);
# Output total tree
print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
printTree($sysTree->[0]);
print "\n";
exit;
sub filterTree
{
my $tree = shift;
my $negativeFilters = shift;
my $positiveFilters = shift;
if (exists $tree->{filter})
{
# Work out how this item in the tree is tagged for filtering
my $itemTags = [split ",", $tree->{filter}];
my @negativeTags;
my @positiveTags;
foreach my $tag (@$itemTags)
{
if ($tag =~ m{^!(.*)})
{
push @negativeTags, $1;
}
else
{
push @positiveTags, $tag;
}
}
# Test whether this item should be removed
if (intersect(\@positiveTags, $negativeFilters) ||
intersect(\@negativeTags, $positiveFilters) )
{
# It should!
# Return false, and the removal will be executed by the
# calling instance
# (No need to examine children)
return 0;
}
# Tidy up the filter attribute
# Remove tags from this item that have been "used up"
# Remove the filter attribute entirely if they have all been
# used up
my %filterLookup = map { $_ => 1 } (@$negativeFilters, @$positiveFilters);
@$itemTags = grep { !exists $filterLookup{$_} } @$itemTags;
if (scalar @$itemTags)
{
$tree->{filter} = join ",", @$itemTags;
}
else
{
delete $tree->{filter};
}
}
# Now iterate through the children of this item and remove any that
# should be filtered out
@{$tree->{Kids}} = grep {
filterTree($_, $negativeFilters, $positiveFilters)
} @{$tree->{Kids}};
# Return true so that the calling instance will preserve this item in
# the output tree
return 1;
}
# Test whether two sets (arrays) intersect
sub intersect
{
my $set1 = shift;
my $set2 = shift;
my %set1 = map { $_ => 1 } @$set1;
foreach (@$set2)
{
return 1 if exists $set1{$_};
}
return 0;
}
sub printTree
{
my $tree = shift or die;
die unless ref $tree;
my $tagName = ref $tree;
$tagName =~ s{^main::}{};
if ($tagName eq "Characters")
{
print $tree->{Text};
return;
}
print "<$tagName";
foreach my $attr (
sort {
my $order = "unofficial name long-name tech_domain level span schema levels filter introduced deprecated purpose class plugin origin-model bldFile mrp version priority";
my $ixA = 1 + index $order, $a or die $a;
my $ixB = 1 + index $order, $b or die $b;
$ixA - $ixB;
}
grep {
! ref $tree->{$_}
}
keys %$tree)
{
print " $attr=\"$tree->{$attr}\"";
}
my $children = $tree->{Kids};
if (scalar @$children)
{
print ">";
foreach my $child (@$children)
{
printTree($child);
}
print "</$tagName";
}
else
{
print "/"
}
print ">";
}