common/tools/sysModelFilter.pl
changeset 457 991d89a55c87
child 1316 0b4a09013baf
equal deleted inserted replaced
456:1ba3c86ebec0 457:991d89a55c87
       
     1 #!perl -w
       
     2 
       
     3 use strict;
       
     4 
       
     5 use XML::Parser;
       
     6 
       
     7 my $sysModel = shift or die "First arg must be system model xml file";
       
     8 my @filters = @ARGV or die "Subsequent arg(s) must be filter(s) to apply";
       
     9 
       
    10 # Sort out the positive and negative filters specified
       
    11 my @negativeFilters;
       
    12 my @positiveFilters;
       
    13 foreach my $filter (@filters)
       
    14 {
       
    15 	if ($filter =~ m{^!(.*)})
       
    16 	{
       
    17 		push @negativeFilters, $1;
       
    18 	}
       
    19 	else
       
    20 	{
       
    21 		push @positiveFilters, $filter;
       
    22 	}
       
    23 }
       
    24 
       
    25 # Read input tree
       
    26 my $parser = new XML::Parser(Style => "Objects") or die;
       
    27 my $sysTree = eval { $parser->parsefile($sysModel) } or die "Failed to parse $sysModel : $@";
       
    28 
       
    29 # Apply filter
       
    30 filterTree($sysTree->[0], \@negativeFilters, \@positiveFilters);
       
    31 
       
    32 # Output total tree
       
    33 print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
       
    34 printTree($sysTree->[0]);
       
    35 print "\n";
       
    36 
       
    37 exit;
       
    38 
       
    39 sub filterTree
       
    40 {
       
    41 	my $tree = shift;
       
    42 	my $negativeFilters = shift;
       
    43 	my $positiveFilters = shift;
       
    44 
       
    45 	if (exists $tree->{filter})
       
    46 	{
       
    47 		# Work out how this item in the tree is tagged for filtering
       
    48 		my $itemTags = [split ",", $tree->{filter}];
       
    49 		my @negativeTags;
       
    50 		my @positiveTags;
       
    51 		foreach my $tag (@$itemTags)
       
    52 		{
       
    53 			if ($tag =~ m{^!(.*)})
       
    54 			{
       
    55 				push @negativeTags, $1;
       
    56 			}
       
    57 			else
       
    58 			{
       
    59 				push @positiveTags, $tag;
       
    60 			}
       
    61 		}
       
    62 
       
    63 		# Test whether this item should be removed
       
    64 		if (intersect(\@positiveTags, $negativeFilters) ||
       
    65 		    intersect(\@negativeTags, $positiveFilters) )
       
    66 		{
       
    67 			# It should!
       
    68 			# Return false, and the removal will be executed by the
       
    69 			# calling instance
       
    70 			# (No need to examine children)
       
    71 			return 0;
       
    72 		}
       
    73 
       
    74 		# Tidy up the filter attribute
       
    75 		# Remove tags from this item that have been "used up"
       
    76 		# Remove the filter attribute entirely if they have all been
       
    77 		# used up
       
    78 		my %filterLookup = map { $_ => 1 } (@$negativeFilters, @$positiveFilters);
       
    79 		@$itemTags = grep { !exists $filterLookup{$_} } @$itemTags;
       
    80 		if (scalar @$itemTags)
       
    81 		{
       
    82 			$tree->{filter} = join ",", @$itemTags;
       
    83 		}
       
    84 		else
       
    85 		{
       
    86 			delete $tree->{filter};
       
    87 		}
       
    88 	}
       
    89 
       
    90 	# Now iterate through the children of this item and remove any that
       
    91 	# should be filtered out
       
    92 	@{$tree->{Kids}} = grep {
       
    93 		filterTree($_, $negativeFilters, $positiveFilters)
       
    94 	} @{$tree->{Kids}};
       
    95 
       
    96 	# Return true so that the calling instance will preserve this item in
       
    97 	# the output tree
       
    98 	return 1;
       
    99 }
       
   100 
       
   101 # Test whether two sets (arrays) intersect
       
   102 sub intersect
       
   103 {
       
   104 	my $set1 = shift;
       
   105 	my $set2 = shift;
       
   106 
       
   107 	my %set1 = map { $_ => 1 } @$set1;
       
   108 	foreach (@$set2)
       
   109 	{
       
   110 		return 1 if exists $set1{$_};
       
   111 	}
       
   112 	return 0;
       
   113 }
       
   114 
       
   115 sub printTree
       
   116 {
       
   117 	my $tree = shift or die;
       
   118 	die unless ref $tree;
       
   119 
       
   120 	my $tagName = ref $tree;
       
   121 	$tagName =~ s{^main::}{};
       
   122 	if ($tagName eq "Characters")
       
   123 	{
       
   124 		print $tree->{Text};
       
   125 		return;
       
   126 	}
       
   127 	
       
   128 	print "<$tagName";
       
   129 
       
   130 	foreach my $attr (
       
   131 		sort {
       
   132 			my $order = "unofficial name long-name tech_domain level span schema levels filter introduced deprecated purpose class plugin origin-model bldFile mrp version priority";
       
   133 			my $ixA = 1 + index $order, $a or die $a;
       
   134 			my $ixB = 1 + index $order, $b or die $b;
       
   135 			$ixA - $ixB;
       
   136 		}
       
   137 		grep {
       
   138 			! ref $tree->{$_}
       
   139 		}
       
   140 		keys %$tree)
       
   141 	{
       
   142 		print " $attr=\"$tree->{$attr}\"";
       
   143 	}
       
   144 
       
   145 	my $children = $tree->{Kids};
       
   146 	if (scalar @$children)
       
   147 	{
       
   148 		print ">";
       
   149 		foreach my $child (@$children)
       
   150 		{
       
   151 			printTree($child);
       
   152 		}
       
   153 		print "</$tagName";
       
   154 	}
       
   155 	else
       
   156 	{
       
   157 		print "/"
       
   158 	}
       
   159 
       
   160 	print ">";
       
   161 }
       
   162