Script to merge multiple MXL files together, according to a merge specification string
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/common/tools/mergeXML.pl Fri Oct 02 12:25:56 2009 +0100
@@ -0,0 +1,190 @@
+#!perl -w
+# Copyright (c) 2009 Symbian Foundation Ltd
+# This component and the accompanying materials are made available
+# under the terms of the License "Eclipse Public License v1.0"
+# which accompanies this distribution, and is available
+# at the URL "http://www.eclipse.org/legal/epl-v10.html".
+#
+# Initial Contributors:
+# Symbian Foundation Ltd - initial contribution.
+#
+# Contributors:
+#
+# Description:
+# Merge a set of XML files
+
+use strict;
+
+use XML::Parser;
+use Getopt::Long;
+
+# Read option arguments
+my $howtoString;
+my $xslLink;
+my $help;
+GetOptions((
+ 'xsl=s' => \$xslLink,
+ 'merge=s' => \$howtoString,
+ 'help!' => \$help,
+));
+
+my $wrongArgs = 0;
+unless ($help)
+{
+ $wrongArgs += warn "No merge string specified to indicate how the files should be merged\n" unless defined $howtoString;
+ $wrongArgs += warn "No files to be merged\n" unless scalar @ARGV;
+}
+if ($help || $wrongArgs)
+{
+ print <<"EOT";
+
+mergeXML.pl --xsl=brag.xsl --merge=SystemDefinition,systemModel,layer(name),block(name),package(name) sysModel1.xml [model2.xml ...] > output.xml
+EOT
+ exit(0 + !$help);
+}
+
+# Hash of tags that should be merged, with optional attribute consideration
+my $mergeTags;
+foreach my $term (split m{\s*,\s*}, $howtoString)
+{
+ my ($tag, $attribute) = $term =~ m{(\w+)\((\w+)\)};
+ $tag ||= $term;
+ $mergeTags->{$tag} = $attribute;
+}
+
+# Merge all the trees together
+my $outTree = mergeMultipleTrees($mergeTags, @ARGV);
+
+# Output total tree
+print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+print "<?xml-stylesheet type=\"text/xsl\" href=\"$xslLink\"?>\n" if $xslLink;
+printTree($outTree->[0]);
+print "\n";
+
+exit(0);
+
+sub mergeMultipleTrees
+{
+ my $mergeTags = shift or die;
+
+ # Create an XML parser
+ my $parser = new XML::Parser(Style => "Objects") or die;
+
+ my $outTree;
+ # For each XML file to merge...
+ foreach my $xmlFile (@_)
+ {
+ my $tree = eval { $parser->parsefile($xmlFile) } or die "Failed to parse $xmlFile : $@";
+ if (!$outTree)
+ {
+ # The first file is taken verbatim
+ $outTree = $tree;
+ }
+ else
+ {
+ # Merge into output Tree
+ mergeTwoTrees($outTree->[0], $tree->[0], $mergeTags);
+ }
+ }
+
+ return $outTree;
+}
+
+sub mergeTwoTrees
+{
+ my $baseTree = shift or die;
+ my $extrasTree = shift or die;
+ my $mergeTags = shift or die;
+
+ die ("Trees do not match: ".(ref $baseTree)." vs ".(ref $extrasTree)) unless ref $baseTree eq ref $extrasTree;
+ return if ref $baseTree eq "main::Characters";
+
+ foreach my $extraChild (@{$extrasTree->{Kids}})
+ {
+ # Work out whether this child should be merged with a namesake, or appended
+ my $mergeIt;
+
+ my $extraChildTag = ref $extraChild;
+ $extraChildTag =~ s{^main::}{};
+
+ if (exists $mergeTags->{$extraChildTag})
+ {
+ # Should be merged if there's already one there
+ # Look for a namesake in the base
+ $mergeIt = matchTag($baseTree->{Kids}, $extraChild, $mergeTags->{$extraChildTag});
+ }
+
+ if ($mergeIt)
+ {
+ # Merge children
+ mergeTwoTrees($mergeIt, $extraChild, $mergeTags);
+ }
+ else
+ {
+ # Add this child
+ push @{$baseTree->{Kids}}, $extraChild;
+ }
+ }
+}
+
+sub matchTag
+{
+ my $peers = shift;
+ my $outsider = shift;
+ my $attr = shift;
+
+ foreach my $peer (@$peers)
+ {
+ if (ref $peer eq ref $outsider && (!defined $attr || $peer->{$attr} eq $outsider->{$attr}))
+ {
+ return $peer;
+ }
+ }
+
+ return undef;
+}
+
+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
+ 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 ">";
+}
+
+