buildframework/helium/sf/java/sysdef/demo/data/sf/os/buildtools/bldsystemtools/sysdeftools/mergesysdef-module.xsl
changeset 628 7c4a911dc066
parent 588 c7c26511138f
child 629 541af5ee3ed9
equal deleted inserted replaced
588:c7c26511138f 628:7c4a911dc066
     1 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common"  exclude-result-prefixes="exslt">
       
     2 <!--Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 	All rights reserved.
       
     4 	This component and the accompanying materials are made available
       
     5 	under the terms of "Eclipse Public License v1.0"
       
     6 	which accompanies this distribution, and is available
       
     7 	at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 
       
     9 	Initial Contributors:
       
    10 	Nokia Corporation - initial contribution.
       
    11 	Contributors:
       
    12 	Description:
       
    13 	XSLT module for merging only two sysdef files according to the 3.0.0 rules. Old syntax not supported and must be converetd before calling.
       
    14 -->
       
    15 	
       
    16 <xsl:variable name="defaultnamespace">http://www.symbian.org/system-definition</xsl:variable>
       
    17 
       
    18 <xsl:template match="/SystemDefinition[starts-with(@schema,'2.') or starts-with(@schema,'1.')]" priority="2" mode="merge-models">
       
    19 	<xsl:message terminate="yes">ERROR: Syntax <xsl:value-of select="@schema"/> not supported</xsl:message>
       
    20 </xsl:template>
       
    21 <xsl:template match="/SystemDefinition[not(systemModel)]" priority="2" mode="merge-models">
       
    22 	<xsl:message terminate="yes">ERROR: Can only merge stand-alone system models</xsl:message>
       
    23 </xsl:template>
       
    24 
       
    25 <!-- stuff for dealing with namespaces -->
       
    26 
       
    27 
       
    28 <xsl:template match="node()|@*" mode="translate-namespaces"><xsl:copy-of select="."/></xsl:template>
       
    29 <!-- don't translate meta or unit tags, just copy verbatim -->
       
    30 <xsl:template match="meta|unit" mode="translate-namespaces" priority="2">
       
    31 <xsl:element name="{name()}">
       
    32 <xsl:copy-of select="@*|*|comment()"/>
       
    33 </xsl:element>
       
    34 </xsl:template>
       
    35 
       
    36 <xsl:template match="*" mode="translate-namespaces"><xsl:param name="nsdoc"/>
       
    37 <xsl:element name="{name()}">
       
    38 <xsl:apply-templates select="@*|node()" mode="translate-namespaces">
       
    39 	<xsl:with-param name="nsdoc" select="$nsdoc"/>
       
    40 </xsl:apply-templates>
       
    41 </xsl:element>
       
    42 </xsl:template>
       
    43 
       
    44 
       
    45 <xsl:template match="@id|@before" mode="translate-namespaces"><xsl:param name="nsdoc"/>
       
    46 	<xsl:attribute name="{name()}">
       
    47 		<xsl:variable name="id">
       
    48 			<xsl:choose>
       
    49 				<xsl:when test="contains(.,':')">
       
    50 					<xsl:value-of select="substring-after(.,':')"/>
       
    51 				</xsl:when>
       
    52 				<xsl:otherwise>
       
    53 					<xsl:value-of select="."/>
       
    54 				</xsl:otherwise>
       
    55 			</xsl:choose>
       
    56 		</xsl:variable>
       
    57 		<xsl:variable name="ns">
       
    58 			<xsl:choose>
       
    59 				<xsl:when test="contains(.,':')">
       
    60 					<xsl:value-of select="ancestor-or-self::*/namespace::*[name()=substring-before(current()/.,':')]"/>
       
    61 				</xsl:when>
       
    62 				<xsl:when test="/SystemDefinition/@id-namespace">
       
    63 					<xsl:value-of select="/SystemDefinition/@id-namespace"/>
       
    64 				</xsl:when>
       
    65 				<xsl:otherwise>
       
    66 					<xsl:value-of select="$defaultnamespace"/>
       
    67 				</xsl:otherwise>
       
    68 			</xsl:choose>
       
    69 		</xsl:variable>
       
    70 		<xsl:choose>
       
    71 			<xsl:when test="not($nsdoc/@id-namespace) and $defaultnamespace=$ns">
       
    72 				<xsl:value-of select="$id"/>
       
    73 			</xsl:when>
       
    74 			<xsl:when test="$nsdoc/@id-namespace=$ns">
       
    75 				<xsl:value-of select="$id"/>
       
    76 			</xsl:when>
       
    77 			<xsl:when test="$nsdoc/namespace::*[.=$ns]">
       
    78 				<xsl:value-of select="concat(name($nsdoc/namespace::*[.=$ns]),':',$id)"/>
       
    79 			</xsl:when>
       
    80 			<xsl:when test="/SystemDefinition/@id-namespace=$ns">
       
    81 				<xsl:variable name="myns">
       
    82 					<xsl:apply-templates mode="ns-prefix" select="$nsdoc">
       
    83 						<xsl:with-param name="ns" select="$ns"/>
       
    84 					</xsl:apply-templates>
       
    85 				</xsl:variable>			
       
    86 				<xsl:value-of select="concat($myns,':',$id)"/>
       
    87 			</xsl:when>
       
    88 			<xsl:otherwise> <!-- some namespace that needed to be defined --> 
       
    89 			<xsl:message>Warning: need definition for namespace "<xsl:value-of select="$ns"/>" for <xsl:value-of select="$id"/></xsl:message>
       
    90 				<xsl:value-of select="."/>					
       
    91 			</xsl:otherwise>
       
    92 		</xsl:choose>		
       
    93 	</xsl:attribute>
       
    94 </xsl:template>
       
    95 
       
    96 <xsl:template match="/SystemDefinition" mode="ns-prefix">
       
    97 	<xsl:param name="ns"/> <!-- the namespace URI -->
       
    98 	<xsl:param name="pre"/> <!-- the preferred prefix to use if possbile -->
       
    99 	<xsl:param name="dontuse"/> <!-- space prefixed, separated and terminated list of namespace prefixes to not use -->
       
   100 	<xsl:param name="chars">ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz</xsl:param> <!-- single letter namespace prefixes to try -->
       
   101 	<xsl:variable name="name" select="substring(substring-after($ns,'http://www.'),1,1)"/>
       
   102 	<xsl:choose>
       
   103 		<xsl:when test="$pre!='' and $pre!='id-namespace' and not(//namespace::*[name()=$pre]) and not(contains($dontuse,concat(' ',$pre,' ')))">
       
   104 			<xsl:value-of select="$pre"/>
       
   105 		</xsl:when>
       
   106 		<xsl:when test="$ns='' and $chars=''">
       
   107 			<xsl:message terminate="yes">ERROR: Cannot create namespace prefix for downstream default namespace in <xsl:value-of select="*/@id"/></xsl:message>
       
   108 		</xsl:when>
       
   109 		<xsl:when test="$name!='' and not(contains($dontuse,concat(' ',$name,' ')))"><xsl:value-of select="$name"/></xsl:when>
       
   110 		<xsl:when test="namespace::*[name()=substring($chars,1,1)] or contains($dontuse,concat(' ',substring($chars,1,1),' '))">
       
   111 			<xsl:apply-templates mode="ns-prefix">
       
   112 				<xsl:with-param name="chars" select="substring($chars,2)"/>
       
   113 			</xsl:apply-templates>
       
   114 		</xsl:when>
       
   115 		<xsl:otherwise>
       
   116 			<xsl:value-of select="substring($chars,1,1)"/>
       
   117 		</xsl:otherwise>
       
   118 	</xsl:choose>
       
   119 </xsl:template>
       
   120 
       
   121 
       
   122 <!--  need to make sure this handles <meta> correctly -->
       
   123 
       
   124 <xsl:template match="/SystemDefinition" mode="merge-models">
       
   125 	<xsl:param name="other"/>	<!-- the downstream SystemDefinition this is merged with -->
       
   126 	<xsl:param name="up" select="systemModel"/>	<!-- the element containing the origin @name used for any component from "this" model. -->
       
   127 	<xsl:param name="down" select="$other/systemModel"/> <!-- the element containing origin @name used for any component from $other model. -->
       
   128 	
       
   129 	<!-- do some testing -->
       
   130  	<xsl:if test="$other[starts-with(@schema,'2.') or starts-with(@schema,'1.')]">
       
   131 		<xsl:message terminate="yes">ERROR: Syntax <xsl:value-of select="$other/@schema"/> not supported</xsl:message>
       
   132 	</xsl:if>
       
   133 	<xsl:if test="not($other/systemModel)">
       
   134 		<xsl:message terminate="yes">ERROR: Can only merge stand-alone system models</xsl:message>
       
   135 	</xsl:if>
       
   136 	 
       
   137 	<xsl:copy>
       
   138 		<xsl:copy-of  select="@*"/> <!--  use attributes from origin model -->
       
   139 		<xsl:variable name="namespaces">
       
   140 			<xsl:copy> <!-- needs <copy> so the processor doesn't lose the namespaces -->
       
   141 				<!--copy namespaces as needed -->
       
   142 				
       
   143 				<xsl:copy-of select="namespace::*[name()!='xml']"/> <!-- all upstream namespaces -->
       
   144 
       
   145 				<xsl:variable name="cur" select="."/>
       
   146 				<xsl:for-each select="$other/namespace::*"> <!-- all namespaces in downstream not already in upstream -->
       
   147 					<xsl:if test="not((. = $cur/@id-namespace) or (not($cur/@id-namespace) and .= $defaultnamespace) or  $cur/namespace::*[.=current()])">
       
   148 							<!-- namespace in downstream not in upstream doc -->
       
   149 							<xsl:variable name="newprefix">
       
   150 								 <!-- test to see if the ns prefix already exists -->
       
   151 								<xsl:apply-templates select="$cur" mode="ns-prefix">
       
   152 									<xsl:with-param name="ns" select="."/>
       
   153 									<xsl:with-param name="pre" select="name()"/>
       
   154 								</xsl:apply-templates>
       
   155 							</xsl:variable>
       
   156 							<xsl:copy/>
       
   157 					</xsl:if>   
       
   158 				</xsl:for-each>
       
   159 				
       
   160 					<xsl:if test="not(($other/@id-namespace = @id-namespace) or (not($other/@id-namespace) and not(@id-namespace)) or (not(@id-namespace) and $other/@id-namespace = $defaultnamespace) or namespace::*[.=$other/@id-namespace])">  
       
   161 						<!-- default namespace in downstream not in upstream doc -->
       
   162 						<!-- need to make created ns a bit more intelligent -->
       
   163 						<xsl:attribute name="bar" namespace="{$other/@id-namespace}">
       
   164 							<xsl:value-of select="$other/@id-namespace"/>
       
   165 						</xsl:attribute>
       
   166 				</xsl:if>
       
   167 			</xsl:copy>
       
   168 		</xsl:variable>
       
   169 
       
   170 		
       
   171 		<!-- copy the namespaces to currently open element (the root one) -->
       
   172 		<xsl:copy-of select="namespace::*"/>
       
   173 		<xsl:for-each select="$other/namespace::*[.!=current()/namespace::*]"><xsl:copy/></xsl:for-each>
       
   174 		<xsl:for-each select="exslt:node-set($namespaces)/*/namespace::*"><xsl:copy/></xsl:for-each>
       
   175 	<!-- translate all IDs in downstream doc to use namespaces from upstream doc  
       
   176 		This is so much easier than having to propigate this info around while creating the doc-->
       
   177 	<xsl:variable name="otherdoc">
       
   178 		<xsl:apply-templates mode="translate-namespaces" select="$other">
       
   179 			<xsl:with-param name="nsdoc" select="exslt:node-set($namespaces)/* | ."/>
       
   180 		</xsl:apply-templates>
       
   181 	</xsl:variable>
       
   182 		<xsl:apply-templates mode="merge-models">
       
   183 			<xsl:with-param name="other" select="exslt:node-set($otherdoc)/*"/>
       
   184 			<xsl:with-param name="up" select="$up"/>
       
   185 			<xsl:with-param name="down" select="$down"/>
       
   186 		</xsl:apply-templates>
       
   187 	
       
   188 	</xsl:copy>
       
   189 </xsl:template>
       
   190 
       
   191 <xsl:template match="systemModel" mode="merge-models">
       
   192 	<xsl:param name="other"/>	<!-- the parent of the downstream systemModel this is merged with -->
       
   193 	<xsl:param name="up"/>
       
   194 	<xsl:param name="down"/>
       
   195 	<xsl:copy><xsl:copy-of  select="@*"/>
       
   196 		<!--  copy metas and comments in between meta. Do not try to merge metadata between models -->
       
   197 			<xsl:copy-of select="meta | $other/systemModel/meta | comment()[following-sibling::meta]"/>	
       
   198 		<xsl:apply-templates mode="merge-models">
       
   199 			<xsl:with-param name="other" select="$other/systemModel"/>
       
   200 			<xsl:with-param name="up" select="$up"/>
       
   201 			<xsl:with-param name="down" select="$down"/>
       
   202 		</xsl:apply-templates>
       
   203 	</xsl:copy>
       
   204 </xsl:template>
       
   205 
       
   206 <xsl:template match="@*|*|comment()" mode="merge-models"><xsl:copy-of select="."/></xsl:template>
       
   207 
       
   208 
       
   209 <xsl:template match="meta|comment()[following-sibling::meta]" mode="merge-models"/>
       
   210 	<!-- copy elesewhere, not here so that metas always appear first-->
       
   211 
       
   212 
       
   213 
       
   214 <!-- merge levels attribute via std rules -->
       
   215 <xsl:template match="layer/@levels|package/@levels" mode="merge-models">
       
   216 	<xsl:param name="other"/><!-- the element contains the other @levels -->
       
   217 	<xsl:choose>
       
   218 		<!--  if they are the same, or not specified in the other,  just copy -->
       
   219 		<xsl:when test=".=$other/@levels or not($other/@levels)"><xsl:copy-of select="."/></xsl:when>
       
   220 		<xsl:when test="contains(concat(' ',normalize-space(.),' '),concat(' ',normalize-space($other/@levels),' '))">
       
   221 			<!--upstream completely contains downstream, just copy --> 
       
   222 			<xsl:copy-of select="."/>
       
   223 		</xsl:when>
       
   224 		<xsl:when test="contains(concat(' ',normalize-space($other/@levels),' '),concat(' ',normalize-space(.),' '))">
       
   225 			<!--  If this is contained is other, then use other-->
       
   226 			<xsl:copy-of select="$other/@levels"/>
       
   227 		</xsl:when>
       
   228 		<xsl:when test="contains(concat(' ',normalize-space($other/@levels),' '),' - ')">
       
   229 			<!-- if other uses + syntax, then pre/append -->
       
   230 			<xsl:variable name="lev">
       
   231 				<xsl:value-of select="substring-before(concat(' ',normalize-space($other/@levels),' '),' - ')"/>
       
   232 				<xsl:value-of select="concat(' ',.,' ')"/>
       
   233 				<xsl:value-of select="substring-after(concat(' ',normalize-space($other/@levels),' '),' - ')"/>
       
   234 			</xsl:variable>
       
   235 			<xsl:attribute name="levels"><xsl:value-of select="normalize-space($lev)"/></xsl:attribute>
       
   236 		</xsl:when>
       
   237 		<xsl:otherwise> <!--  if they differ, use the origin's levels -->
       
   238 			<xsl:message>Note: levels differ "<xsl:value-of select="."/>" vs "<xsl:value-of select="$other/@levels"/>"</xsl:message>
       
   239 			<xsl:copy-of select="."/>
       
   240 		</xsl:otherwise>
       
   241 	</xsl:choose>
       
   242 </xsl:template>
       
   243 
       
   244 <xsl:template name="copy-sorted-content">
       
   245 	<xsl:param name="base"/>
       
   246 	<xsl:param name="to-sort"/>
       
   247 	<xsl:param name="start"/>
       
   248 	<xsl:param name="end"/>
       
   249 	<xsl:param name="down"/>
       
   250 	<xsl:param name="remainder" select="/.."/>
       
   251 
       
   252 	<xsl:choose>
       
   253 		<xsl:when test="not($to-sort)"/>  <!-- nothing left to copy. stop -->
       
   254 		<xsl:when test="not($base)"/>  <!-- reached end. stop -->
       
   255 		<xsl:when test="$base[1]/@id=$end/following-sibling::*[1]/@id"/> <!-- passed $end. Stop -->
       
   256 		<xsl:when test="$base[1]/@id = $to-sort[1]/@id">  <!-- both lists start with same item -->
       
   257 			<xsl:if test="$base[1]/@id!=$end/@id"> <!-- not at end, so keep going -->
       
   258 				<xsl:call-template name="copy-sorted-content">
       
   259 					<xsl:with-param name="base" select="$base[position() != 1]"/>
       
   260 					<xsl:with-param name="to-sort" select="$to-sort[position() != 1]"/>
       
   261 					<xsl:with-param name="remainder" select="$remainder"/>
       
   262 					<xsl:with-param name="start" select="$start"/>
       
   263 					<xsl:with-param name="end" select="$end"/>
       
   264 					<xsl:with-param name="down" select="$down"/>
       
   265 				</xsl:call-template>		
       
   266 			</xsl:if>
       
   267 		</xsl:when>	
       
   268 		<xsl:when test="$remainder[@id = $base[1]/@id]"> <!-- left over item is in $base -->
       
   269 			<xsl:call-template name="copy-sorted-content">
       
   270 				<xsl:with-param name="base" select="$base[position() != 1]"/>
       
   271 				<xsl:with-param name="to-sort" select="$to-sort"/>
       
   272 				<xsl:with-param name="remainder" select="$remainder[@id != $base[1]/@id]"/>
       
   273 				<xsl:with-param name="start" select="$start"/>
       
   274 				<xsl:with-param name="end" select="$end"/>
       
   275 				<xsl:with-param name="down" select="$down"/>
       
   276 			</xsl:call-template>		
       
   277 		</xsl:when>
       
   278 		<xsl:when test="not($base[@id = $to-sort[1]/@id])"> <!-- in to-sort, but not base -->		
       
   279 			<xsl:if test="$base[1]/@id=$end/@id  and not($base[@id=$to-sort[1]/@before])">
       
   280 			 	<!-- if at end, then this needs to be copied
       
   281 					don't copy if the before ID is found in $base	-->
       
   282 				<xsl:apply-templates mode="merge-copy-of" select="$to-sort[1]">
       
   283 					<xsl:with-param name="origin" select="$down"/>
       
   284 					<xsl:with-param name="root" select="$end/ancestor::systemModel"/>
       
   285 				</xsl:apply-templates>
       
   286 			</xsl:if>			
       
   287 		<xsl:call-template name="copy-sorted-content">
       
   288 			<xsl:with-param name="base" select="$base"/>
       
   289 			<xsl:with-param name="to-sort" select="$to-sort[position() != 1]"/>
       
   290 			<xsl:with-param name="remainder" select="$remainder"/>
       
   291 			<xsl:with-param name="start" select="$start"/>
       
   292 			<xsl:with-param name="end" select="$end"/>
       
   293 			<xsl:with-param name="down" select="$down"/>
       
   294 		</xsl:call-template>		
       
   295 		</xsl:when>	
       
   296 		<xsl:when test="not($to-sort[@id = $base[1]/@id])"> <!-- in base, but not to-sort -->		
       
   297 		<xsl:call-template name="copy-sorted-content">
       
   298 			<xsl:with-param name="base" select="$base[position() != 1]"/>
       
   299 			<xsl:with-param name="to-sort" select="$to-sort"/>
       
   300 			<xsl:with-param name="remainder" select="$remainder"/>
       
   301 			<xsl:with-param name="start" select="$start"/>
       
   302 			<xsl:with-param name="end" select="$end"/>
       
   303 			<xsl:with-param name="down" select="$down"/>
       
   304 		</xsl:call-template>		
       
   305 		</xsl:when>	
       
   306 		<xsl:when test="$base[@id = $to-sort[1]/@id]"> <!-- is in base, but not 1st one-->
       
   307 			<xsl:call-template name="copy-sorted-content">
       
   308 				<xsl:with-param name="base" select="$base"/>
       
   309 				<xsl:with-param name="to-sort" select="$to-sort[position() != 1] "/>
       
   310 				<xsl:with-param name="remainder" select="$remainder | $to-sort[1]"/>
       
   311 				<xsl:with-param name="start" select="$start"/>
       
   312 				<xsl:with-param name="end" select="$end"/>
       
   313 				<xsl:with-param name="down" select="$down"/>
       
   314 			</xsl:call-template>
       
   315 		</xsl:when>	
       
   316 	</xsl:choose>
       
   317 </xsl:template>
       
   318 
       
   319 <xsl:template match="layer | package | collection | component" mode="merge-models">
       
   320 	<xsl:param name="other"/>	<!-- the downstream item of the parent's rank that contains a potential items this is merged with -->
       
   321 	<xsl:param name="up"/>
       
   322 	<xsl:param name="down"/>
       
   323 	<xsl:variable name="this" select="."/>	<!-- current item -->
       
   324 	
       
   325 	<!-- match = this item in the downstream model -->	
       
   326 	<xsl:variable name="match" select="$other/*[@id=current()/@id]"/>
       
   327 	
       
   328 	<!-- prev = the previous item before the current one (no metas, only named items)-->
       
   329 	<xsl:variable name="prev" select="preceding-sibling::*[@id][1]"/> 
       
   330 
       
   331 	<!-- copy all items between this and prev  that are solely in the downstream model -->	 		
       
   332 
       
   333 	<xsl:choose>
       
   334 		<xsl:when test="$match and (not($prev) or $other/*[@id= $prev/@id] )">
       
   335 			<xsl:call-template name="copy-sorted-content">
       
   336 				<xsl:with-param name="base" select="../*[@id]"/>
       
   337 				<xsl:with-param name="to-sort" select="$other/*[@id]"/>
       
   338 				<xsl:with-param name="start" select="$prev"/>
       
   339 				<xsl:with-param name="end" select="."/>
       
   340 				<xsl:with-param name="down" select="$down"/>
       
   341 			</xsl:call-template>
       
   342 		</xsl:when>
       
   343 	<xsl:when test="not($match/preceding-sibling::*[@id=$this/../*/@id]) and $other/*[@id= current()/@id]/preceding-sibling::*[@id and not(@before)]">
       
   344 		<!-- if this is the first item in other that's also in this, then put all new items from other here -->
       
   345 		<xsl:apply-templates mode="merge-copy-of" select="$match/preceding-sibling::*[@id and not(@before)]">
       
   346 			<xsl:with-param name="origin" select="$down"/>
       
   347 			<xsl:with-param name="root" select="$this/ancestor::systemModel"/>	
       
   348 		</xsl:apply-templates>
       
   349 	</xsl:when>
       
   350 	</xsl:choose>
       
   351 
       
   352  	<!-- just copy anything identified as being before this, assume they're all ok -->
       
   353 	<xsl:apply-templates mode="merge-copy-of" select="$other/*[@before=current()/@id]">
       
   354 		<xsl:with-param name="remove-before" select="1"/>
       
   355 		<xsl:with-param name="origin" select="$down"/>
       
   356 		<xsl:with-param name="root" select="$this/ancestor::systemModel"/>	
       
   357 	</xsl:apply-templates>
       
   358 
       
   359 	
       
   360 	<xsl:copy>
       
   361 		<xsl:apply-templates select="@*" mode="merge-models"> <!-- copy upstream attributes -->
       
   362 			<xsl:with-param name="other" select="$match"/>
       
   363 		</xsl:apply-templates>
       
   364 		
       
   365 		<xsl:if test="self::component and not(@origin-model) and $up/@name">
       
   366 			<!-- insert origin-model and optional root for components only -->
       
   367 			<xsl:attribute name="origin-model">
       
   368 				<xsl:value-of select="$up/@name"/>
       
   369 			</xsl:attribute>
       
   370 			<xsl:if test="not(@root)">
       
   371 				<xsl:copy-of select="$up/@root"/>
       
   372 			</xsl:if>
       
   373 		</xsl:if>
       
   374 		
       
   375 		<xsl:for-each select="$match/@*">  <!-- copy downstream attributes, only if not set on upstream -->
       
   376 			<xsl:if test="not($this/@*[name()=name(current())])"><xsl:copy-of select="."/></xsl:if>
       
   377 		</xsl:for-each>
       
   378 		
       
   379 		<xsl:choose>
       
   380 			<xsl:when test="self::component">
       
   381 				<!-- copy all units, metas and comments from this
       
   382 					copy all metas in the merged component
       
   383 					copy any new comments in the merged component (not duplicates)
       
   384 					if there are no units in the this, copy all units in the merged component
       
   385 					if there are units in this, copy only the versioned units in the merged component (only those versions not already specified) -->
       
   386 				<xsl:copy-of select="*|comment() | $match/meta |$match/unit[not($this/unit)] | $match/unit[$this/unit and @version[.!=$this/unit/@version]] | $match/comment()[.!=$this/comment()]"/>				
       
   387 			</xsl:when>
       
   388 			<xsl:otherwise>
       
   389 
       
   390 				<!--  copy metas and comments in between meta. Do not try to merge metadata between models -->
       
   391 				<xsl:copy-of select="meta | $match/meta | comment()[following-sibling::meta]"/>
       
   392 				
       
   393 				<xsl:apply-templates mode="merge-models">
       
   394 					<xsl:with-param name="other" select="$match"/>
       
   395 					<xsl:with-param name="up" select="$up"/>
       
   396 					<xsl:with-param name="down" select="$down"/>
       
   397 				</xsl:apply-templates>
       
   398 				<!--  don't copy if explicitly or implicitly placed already-->
       
   399 				<xsl:for-each select="$match/*[not(@before) and not(following-sibling::*[@id=$this/*/@id])]">
       
   400 					<xsl:if test="not($this/*[@id=current()/@id])">
       
   401 						<xsl:apply-templates mode="merge-copy-of" select=".">
       
   402 							<xsl:with-param name="origin" select="$down"/>
       
   403 							<xsl:with-param name="root" select="$this/ancestor::systemModel"/>			
       
   404 						</xsl:apply-templates>
       
   405 					</xsl:if>
       
   406 				</xsl:for-each>
       
   407 			</xsl:otherwise>
       
   408 		</xsl:choose>
       
   409 	</xsl:copy>
       
   410 	
       
   411 	<xsl:if test="self::layer and not(following-sibling::layer)">
       
   412 		<!-- for the last layer, tack on any remaining layers -->
       
   413 		<xsl:apply-templates mode="merge-copy-of" select="$other/layer[not(@before) and not(following-sibling::*[@id=$this/../layer/@id]) and not(@id=$this/../layer/@id)]">
       
   414 			<xsl:with-param name="origin" select="$down"/>
       
   415 			<xsl:with-param name="root" select="$this/ancestor::systemModel"/>			
       
   416 		</xsl:apply-templates>		
       
   417 	</xsl:if>
       
   418 </xsl:template>
       
   419 
       
   420 
       
   421 
       
   422 <xsl:template match="*" mode="merge-copy-of">
       
   423 	<xsl:param name="remove-before" select="0"/> <!-- set to true if any before attribute is to be removed -->
       
   424 	<xsl:param name="origin"/>	<!--the element containing the @name to use the origin-model attribute  -->
       
   425 	<xsl:param name="root"/> 	<!--the systemModel element in the upstream doc  -->
       
   426 
       
   427 	<xsl:choose>
       
   428 		<!-- this might slow things down, consider making optional -->
       
   429 		<xsl:when test="not(self::layer) and count($root/descendant::*[name()=name(current()/..) and @id!=current()/../@id]/*[@id=current()/@id])">
       
   430 			<xsl:message>Warning: <xsl:value-of select="name()"/> "<xsl:value-of select="@id"/>" moved in downstream model. Ignoring moved <xsl:value-of select="name()"/>
       
   431 				<xsl:text>&#xa;</xsl:text>
       
   432 			</xsl:message>
       
   433 		</xsl:when>
       
   434 		<xsl:otherwise>
       
   435 			<!-- save all content in a variable to test to see if it's got any problems (ie been removed due to errors)-->
       
   436 			<xsl:variable name="content">
       
   437 				<xsl:apply-templates select="*|comment()" mode="merge-copy-of">
       
   438 					<xsl:with-param name="origin" select="$origin"/>
       
   439 					<xsl:with-param name="root" select="$root"/>
       
   440 				</xsl:apply-templates>
       
   441 			</xsl:variable>
       
   442 			<xsl:choose>
       
   443 				<!-- if all elements in this have been deleted, throw out this element -->
       
   444 				<xsl:when test="not(exslt:node-set($content)/*) and *">
       
   445 					<xsl:message>Warning: All content in downstream <xsl:value-of select="name()"/> "<xsl:value-of select="@id"/>" is invalid. Ignoring <xsl:value-of select="name()"/>
       
   446 						<xsl:text>&#xa;</xsl:text>
       
   447 					</xsl:message>
       
   448 				</xsl:when>
       
   449 				<xsl:otherwise>
       
   450 					<xsl:copy>
       
   451 						<xsl:choose>
       
   452 							<xsl:when test="$remove-before">
       
   453 								<xsl:copy-of select="@*[name()!='before']"/>
       
   454 							</xsl:when>
       
   455 							<xsl:otherwise><xsl:copy-of select="@*"/></xsl:otherwise>
       
   456 						</xsl:choose>
       
   457 						<xsl:copy-of select="exslt:node-set($content)"/>
       
   458 					</xsl:copy>
       
   459 				</xsl:otherwise>
       
   460 			</xsl:choose>					
       
   461 		</xsl:otherwise>
       
   462 	</xsl:choose>
       
   463 </xsl:template>
       
   464 
       
   465 
       
   466 <xsl:template match="comment()|@*" mode="merge-copy-of">
       
   467 	<xsl:copy-of select="."/>
       
   468 </xsl:template>
       
   469 
       
   470 <xsl:template match="component" mode="merge-copy-of">
       
   471 	<xsl:param name="remove-before" select="0"/> <!-- set to true if any before attribute is to be removed -->
       
   472 	<xsl:param name="origin"/>	<!--the element containing the @name to use the origin-model attribute  -->
       
   473 	<xsl:param name="root"/> 	<!--the systemModel element in the upstream doc  -->
       
   474 	
       
   475 	<xsl:choose>
       
   476 		<!-- this might slow things down, consider making optional -->
       
   477 		<xsl:when test="$root/descendant::collection[@id!=current()/../@id]/component[@id=current()/@id]">
       
   478 			<xsl:message>Warning: <xsl:value-of select="name()"/> "<xsl:value-of select="@id"/>" moved in downstream model. Ignoring moved <xsl:value-of select="name()"/>
       
   479 				<xsl:text>&#xa;</xsl:text>
       
   480 			</xsl:message>
       
   481 		</xsl:when>
       
   482 		<xsl:otherwise>
       
   483 			<xsl:copy>
       
   484 				<xsl:choose>
       
   485 					<xsl:when test="$remove-before">
       
   486 						<xsl:copy-of select="@*[name()!='before']"/>
       
   487 					</xsl:when>
       
   488 					<xsl:otherwise><xsl:copy-of select="@*"/></xsl:otherwise>
       
   489 				</xsl:choose>
       
   490 				<xsl:if test="not(@origin-model) and $origin/@name">
       
   491 					<xsl:attribute name="origin-model">
       
   492 						<xsl:value-of select="$origin/@name"/>
       
   493 					</xsl:attribute>
       
   494 					<xsl:if test="not(@root)">
       
   495 						<xsl:copy-of select="$origin/@root"/>
       
   496 					</xsl:if>
       
   497 				</xsl:if>
       
   498 				<xsl:copy-of select="*|comment()"/>
       
   499 			</xsl:copy>
       
   500 		</xsl:otherwise>
       
   501 	</xsl:choose>
       
   502 </xsl:template>
       
   503 
       
   504 </xsl:stylesheet>