# HG changeset patch # User Simon Howkins # Date 1254482756 -3600 # Node ID e5e6ae6bf38f2c10ad27c241f61a1a63e87ac7e0 # Parent 5af7cc0d44a1e7109c5f293bf7e8c4fe48cbf435 Script to merge multiple MXL files together, according to a merge specification string diff -r 5af7cc0d44a1 -r e5e6ae6bf38f common/tools/mergeXML.pl --- /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 "\n"; +print "\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 ""; +} + +