sysmodellibs/sysmodelgen/core/mergesysdef-module.xsl
changeset 7 3c36c452f013
equal deleted inserted replaced
6:5b32dc297d05 7:3c36c452f013
       
     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 the License "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.1 rules. 
       
    14 		2.x and older syntax not supported and must be converted before calling.
       
    15 
       
    16 		Requires the including XSLT to also include path-module.xsl
       
    17 -->
       
    18 	
       
    19 <xsl:variable name="defaultnamespace">http://www.symbian.org/system-definition</xsl:variable>
       
    20 
       
    21 <xsl:template match="/SystemDefinition[starts-with(@schema,'2.') or starts-with(@schema,'1.')]" priority="2" mode="merge-models">
       
    22 	<xsl:message terminate="yes">ERROR: Syntax <xsl:value-of select="@schema"/> not supported</xsl:message>
       
    23 </xsl:template>
       
    24 <!--<xsl:template match="/SystemDefinition[not(systemModel)]" priority="2" mode="merge-models">
       
    25 	<xsl:message terminate="yes">ERROR: Can only merge stand-alone system models</xsl:message>
       
    26 </xsl:template>-->
       
    27 
       
    28 <!-- stuff for dealing with namespaces -->
       
    29 
       
    30 
       
    31 <xsl:template match="node()|@*" mode="translate-namespaces"><xsl:copy-of select="."/></xsl:template>
       
    32 <!-- don't translate meta or unit tags, just copy verbatim -->
       
    33 <xsl:template match="meta|unit" mode="translate-namespaces" priority="2">
       
    34 <xsl:element name="{name()}">
       
    35 <xsl:copy-of select="@*|*|comment()"/>
       
    36 </xsl:element>
       
    37 </xsl:template>
       
    38 
       
    39 <xsl:template match="*" mode="translate-namespaces"><xsl:param name="nsdoc"/>
       
    40 <xsl:element name="{name()}">
       
    41 <xsl:apply-templates select="@*|node()" mode="translate-namespaces">
       
    42 	<xsl:with-param name="nsdoc" select="$nsdoc"/>
       
    43 </xsl:apply-templates>
       
    44 </xsl:element>
       
    45 </xsl:template>
       
    46 
       
    47 
       
    48 <xsl:template match="@id|@before|@replace" mode="translate-namespaces"><xsl:param name="nsdoc"/>
       
    49 	<xsl:attribute name="{name()}">
       
    50 		<xsl:variable name="id">
       
    51 			<xsl:choose>
       
    52 				<xsl:when test="contains(.,':')">
       
    53 					<xsl:value-of select="substring-after(.,':')"/>
       
    54 				</xsl:when>
       
    55 				<xsl:otherwise>
       
    56 					<xsl:value-of select="."/>
       
    57 				</xsl:otherwise>
       
    58 			</xsl:choose>
       
    59 		</xsl:variable>
       
    60 		<xsl:variable name="ns">
       
    61 			<xsl:choose>
       
    62 				<xsl:when test="contains(.,':')">
       
    63 					<xsl:value-of select="ancestor-or-self::*/namespace::*[name()=substring-before(current()/.,':')]"/>
       
    64 				</xsl:when>
       
    65 				<xsl:when test="ancestor::SystemDefinition/@id-namespace">
       
    66 					<xsl:value-of select="ancestor::SystemDefinition/@id-namespace"/>
       
    67 				</xsl:when>
       
    68 				<xsl:otherwise>
       
    69 					<xsl:value-of select="$defaultnamespace"/>
       
    70 				</xsl:otherwise>
       
    71 			</xsl:choose>
       
    72 		</xsl:variable>
       
    73 		<xsl:choose>
       
    74 			<xsl:when test="not($nsdoc/@id-namespace) and $defaultnamespace=$ns">
       
    75 				<xsl:value-of select="$id"/>
       
    76 			</xsl:when>
       
    77 			<xsl:when test="$nsdoc/@id-namespace=$ns">
       
    78 				<xsl:value-of select="$id"/>
       
    79 			</xsl:when>
       
    80 			<xsl:when test="$nsdoc/namespace::*[.=$ns]">
       
    81 				<xsl:value-of select="concat(name($nsdoc/namespace::*[.=$ns]),':',$id)"/>
       
    82 			</xsl:when>
       
    83 			<xsl:when test="ancestor::SystemDefinition/@id-namespace=$ns">
       
    84 				<xsl:variable name="myns">
       
    85 					<xsl:apply-templates mode="ns-prefix" select="$nsdoc">
       
    86 						<xsl:with-param name="ns" select="$ns"/>
       
    87 					</xsl:apply-templates>
       
    88 				</xsl:variable>			
       
    89 				<xsl:value-of select="concat($myns,':',$id)"/>
       
    90 			</xsl:when>
       
    91 			<xsl:otherwise> <!-- some namespace that needed to be defined --> 
       
    92 			<xsl:message>Warning: need definition for namespace "<xsl:value-of select="$ns"/>" for <xsl:value-of select="$id"/></xsl:message>
       
    93 				<xsl:value-of select="."/>					
       
    94 			</xsl:otherwise>
       
    95 		</xsl:choose>		
       
    96 	</xsl:attribute>
       
    97 </xsl:template>
       
    98 
       
    99 <xsl:template match="SystemDefinition" mode="ns-prefix">
       
   100 	<xsl:param name="ns"/> <!-- the namespace URI -->
       
   101 	<xsl:param name="pre"/> <!-- the preferred prefix to use if possbile -->
       
   102 	<xsl:param name="dontuse"/> <!-- space prefixed, separated and terminated list of namespace prefixes to not use -->
       
   103 	<xsl:param name="chars">ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz</xsl:param> <!-- single letter namespace prefixes to try -->
       
   104 	<xsl:variable name="name" select="substring(substring-after($ns,'http://www.'),1,1)"/>
       
   105 	<xsl:choose>
       
   106 		<xsl:when test="$pre!='' and $pre!='id-namespace' and not(//namespace::*[name()=$pre]) and not(contains($dontuse,concat(' ',$pre,' ')))">
       
   107 			<xsl:value-of select="$pre"/>
       
   108 		</xsl:when>
       
   109 		<xsl:when test="$ns='' and $chars=''">
       
   110 			<xsl:message terminate="yes">ERROR: Cannot create namespace prefix for downstream default namespace in <xsl:value-of select="*/@id"/></xsl:message>
       
   111 		</xsl:when>
       
   112 		<xsl:when test="$name!='' and not(contains($dontuse,concat(' ',$name,' ')))"><xsl:value-of select="$name"/></xsl:when>
       
   113 		<xsl:when test="namespace::*[name()=substring($chars,1,1)] or contains($dontuse,concat(' ',substring($chars,1,1),' '))">
       
   114 			<xsl:apply-templates mode="ns-prefix">
       
   115 				<xsl:with-param name="chars" select="substring($chars,2)"/>
       
   116 			</xsl:apply-templates>
       
   117 		</xsl:when>
       
   118 		<xsl:otherwise>
       
   119 			<xsl:value-of select="substring($chars,1,1)"/>
       
   120 		</xsl:otherwise>
       
   121 	</xsl:choose>
       
   122 </xsl:template>
       
   123 
       
   124 
       
   125 <!--  need to make sure this handles <meta> correctly -->
       
   126 
       
   127 <xsl:template match="SystemDefinition" mode="merge-models">
       
   128 	<xsl:param name="other"/>	<!-- the downstream SystemDefinition this is merged with -->
       
   129 	<xsl:param name="up" select="systemModel"/>	<!-- the element containing the origin @name used for any component from "this" model. -->
       
   130 	<xsl:param name="down" select="$other/systemModel"/> <!-- the element containing origin @name used for any component from $other model. -->
       
   131 	
       
   132 	<!-- do some testing -->
       
   133  	<xsl:if test="$other[starts-with(@schema,'2.') or starts-with(@schema,'1.')]">
       
   134 		<xsl:message terminate="yes">ERROR: Syntax <xsl:value-of select="$other/@schema"/> not supported</xsl:message>
       
   135 	</xsl:if>
       
   136 	<xsl:if test="name(*) != name($other/*)">
       
   137 		<xsl:message terminate="yes">ERROR: Can only merge system models of the same rank</xsl:message>
       
   138 	</xsl:if>
       
   139 
       
   140 	<xsl:copy>
       
   141 		<xsl:attribute name="schema">
       
   142 			<xsl:call-template name="compare-versions">
       
   143 				<xsl:with-param name="v1" select="@schema"/>
       
   144 				<xsl:with-param name="v2" select="$other/@schema"/>
       
   145 			</xsl:call-template>
       
   146 		</xsl:attribute>
       
   147 		<xsl:copy-of  select="@*[name()!='schema']"/> <!--  use attributes from origin model -->
       
   148 		<xsl:variable name="namespaces">
       
   149 			<xsl:copy> <!-- needs <copy> so the processor doesn't lose the namespaces -->
       
   150 				<!--copy namespaces as needed -->
       
   151 				
       
   152 				<xsl:copy-of select="namespace::*[name()!='xml']"/> <!-- all upstream namespaces -->
       
   153 
       
   154 				<xsl:variable name="cur" select="."/>
       
   155 				<xsl:for-each select="$other/namespace::*"> <!-- all namespaces in downstream not already in upstream -->
       
   156 					<xsl:if test="not((. = $cur/@id-namespace) or (not($cur/@id-namespace) and .= $defaultnamespace) or  $cur/namespace::*[.=current()])">
       
   157 							<!-- namespace in downstream not in upstream doc -->
       
   158 							<xsl:variable name="newprefix">
       
   159 								 <!-- test to see if the ns prefix already exists -->
       
   160 								<xsl:apply-templates select="$cur" mode="ns-prefix">
       
   161 									<xsl:with-param name="ns" select="."/>
       
   162 									<xsl:with-param name="pre" select="name()"/>
       
   163 								</xsl:apply-templates>
       
   164 							</xsl:variable>
       
   165 							<xsl:copy/>
       
   166 					</xsl:if>   
       
   167 				</xsl:for-each>
       
   168 				
       
   169 					<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])">  
       
   170 						<!-- default namespace in downstream not in upstream doc -->
       
   171 						<!-- need to make created ns a bit more intelligent -->
       
   172 						<xsl:attribute name="bar" namespace="{$other/@id-namespace}">
       
   173 							<xsl:value-of select="$other/@id-namespace"/>
       
   174 						</xsl:attribute>
       
   175 				</xsl:if>
       
   176 			</xsl:copy>
       
   177 		</xsl:variable>
       
   178 
       
   179 		
       
   180 		<!-- copy the namespaces to currently open element (the root one) -->
       
   181 		<xsl:copy-of select="namespace::*"/>
       
   182 		<xsl:for-each select="$other/namespace::*[.!=current()/namespace::*]"><xsl:copy/></xsl:for-each>
       
   183 		<xsl:for-each select="exslt:node-set($namespaces)/*/namespace::*"><xsl:copy/></xsl:for-each>
       
   184 	<!-- translate all IDs in downstream doc to use namespaces from upstream doc  
       
   185 		This is so much easier than having to propigate this info around while creating the doc-->
       
   186 	<xsl:variable name="otherdoc">
       
   187 		<xsl:apply-templates mode="translate-namespaces" select="$other">
       
   188 			<xsl:with-param name="nsdoc" select="exslt:node-set($namespaces)/* | ."/>
       
   189 		</xsl:apply-templates>
       
   190 	</xsl:variable>
       
   191 		<xsl:apply-templates mode="merge-models">
       
   192 			<xsl:with-param name="other" select="exslt:node-set($otherdoc)/*"/>
       
   193 			<xsl:with-param name="up" select="$up"/>
       
   194 			<xsl:with-param name="down" select="$down"/>
       
   195 			<xsl:with-param name="replaces" select="exslt:node-set($otherdoc)//*[self::component or self::collection or self::package or self::layer]/@replace"/>
       
   196 		</xsl:apply-templates>
       
   197 	
       
   198 	</xsl:copy>
       
   199 </xsl:template>
       
   200 
       
   201 <xsl:template match="systemModel" mode="merge-models">
       
   202 	<xsl:param name="other"/>	<!-- the parent of the downstream systemModel this is merged with -->
       
   203 	<xsl:param name="up"/>
       
   204 	<xsl:param name="down"/>
       
   205 	<xsl:param name="replaces"/>
       
   206 	<xsl:copy><xsl:copy-of  select="@*"/>
       
   207 		<!--  copy metas and comments in between meta. Do not try to merge metadata between models -->
       
   208 			<xsl:copy-of select="meta | $other/systemModel/meta | comment()[following-sibling::meta]"/>	
       
   209 		<xsl:apply-templates mode="merge-models">
       
   210 			<xsl:with-param name="other" select="$other/systemModel"/>
       
   211 			<xsl:with-param name="up" select="$up"/>
       
   212 			<xsl:with-param name="down" select="$down"/>
       
   213 			<xsl:with-param name="replaces" select="$replaces"/>
       
   214 		</xsl:apply-templates>
       
   215 
       
   216 		<!-- tack on any remaining layers -->
       
   217 		<xsl:apply-templates mode="merge-copy-of" select="$other/systemModel/layer[not(@before) and not(following-sibling::*[@id=current()/layer/@id]) and not(@id=current()/layer/@id)]">
       
   218 			<xsl:with-param name="origin" select="$down"/>
       
   219 			<xsl:with-param name="root" select="current()/.."/>
       
   220 			<xsl:with-param name="replaces" select="$replaces"/>
       
   221 		</xsl:apply-templates>		
       
   222 
       
   223 		<!-- and now check for error cases, and tack those on -->
       
   224 		<xsl:call-template name="check-and-add-out-of-order-items">
       
   225 			<xsl:with-param name="match" select="$other/systemModel"/>
       
   226 			<xsl:with-param name="down" select="$down"/>
       
   227 			<xsl:with-param name="replaces" select="$replaces"/>
       
   228 		</xsl:call-template> 
       
   229 	</xsl:copy>
       
   230 </xsl:template>
       
   231 
       
   232 <xsl:template name="check-and-add-out-of-order-items"><xsl:param name="match"/><xsl:param name="down"/><xsl:param name="replaces"/>
       
   233 	<xsl:if test="$match">
       
   234 		<!-- determine the order of the children in the upstream and downstream docs --> 
       
   235 		<xsl:variable name="up-order">
       
   236 			<xsl:for-each select="*[@id=$match/*[not(@before)]/@id]"><xsl:value-of select="@id"/><xsl:text> </xsl:text></xsl:for-each>
       
   237 		</xsl:variable>
       
   238 		<xsl:variable name="down-order">
       
   239 			<xsl:for-each select="$match/*[@id = current()/*[not(@before)]/@id]"><xsl:value-of select="@id"/> <xsl:text> </xsl:text></xsl:for-each>
       
   240 		</xsl:variable>
       
   241 
       
   242 		<!-- check for error cases, and tack those on -->
       
   243 		<xsl:if test="$up-order != $down-order">
       
   244 			<xsl:variable name="down-final" select="$match/*[@id = current()/*[not(@before)]/@id][last()]/@id"/>
       
   245 				<!-- the last item in the downstream model that is also in the upstream one -->
       
   246 
       
   247 			<xsl:variable name="out-of-order" select="$match/*[@id][not(@before=current()/*/@id) and not(@id=current()/*/@id) and following-sibling::*[@id=$down-final]]"/>
       
   248 				<!-- contains all items in the downstream model that can't be put in order-->
       
   249 			<xsl:if test="$out-of-order">
       
   250 				<xsl:message>ERROR: Order of <xsl:value-of select="name(*)"/>s in upstream document does not match order in downstream.  The following <xsl:value-of select="name(*)"/>s will be appended to the end<xsl:if test="@id"> of <xsl:value-of select="@id"/></xsl:if>: <xsl:for-each select="$out-of-order"><xsl:value-of select="concat(@id,' ')"/></xsl:for-each></xsl:message>
       
   251 			</xsl:if>
       
   252 			<xsl:apply-templates mode="merge-copy-of" select="$out-of-order">
       
   253 				<xsl:with-param name="origin" select="$down"/>
       
   254 				<xsl:with-param name="root" select="current()/ancestor::SystemDefinition"/>			
       
   255 				<xsl:with-param name="replaces" select="$replaces"/>
       
   256 			</xsl:apply-templates>			
       
   257 		</xsl:if>
       
   258 	</xsl:if>
       
   259 </xsl:template>
       
   260 
       
   261 
       
   262 <xsl:template match="@*|*|comment()" mode="merge-models"><xsl:copy-of select="."/></xsl:template>
       
   263 
       
   264 
       
   265 <xsl:template match="meta|comment()[following-sibling::meta]" mode="merge-models"/>
       
   266 	<!-- copy elesewhere, not here so that metas always appear first-->
       
   267 
       
   268 
       
   269 
       
   270 <!-- merge levels attribute via std rules -->
       
   271 <xsl:template match="layer/@levels|package/@levels" mode="merge-models">
       
   272 	<xsl:param name="other"/><!-- the element contains the other @levels -->
       
   273 	<xsl:choose>
       
   274 		<!--  if they are the same, or not specified in the other,  just copy -->
       
   275 		<xsl:when test=".=$other/@levels or not($other/@levels)"><xsl:copy-of select="."/></xsl:when>
       
   276 		<xsl:when test="contains(concat(' ',normalize-space(.),' '),concat(' ',normalize-space($other/@levels),' '))">
       
   277 			<!--upstream completely contains downstream, just copy --> 
       
   278 			<xsl:copy-of select="."/>
       
   279 		</xsl:when>
       
   280 		<xsl:when test="contains(concat(' ',normalize-space($other/@levels),' '),concat(' ',normalize-space(.),' '))">
       
   281 			<!--  If this is contained is other, then use other-->
       
   282 			<xsl:copy-of select="$other/@levels"/>
       
   283 		</xsl:when>
       
   284 		<xsl:when test="contains(concat(' ',normalize-space($other/@levels),' '),' - ')">
       
   285 			<!-- if other uses - syntax, then pre/append -->
       
   286 			<xsl:variable name="lev">
       
   287 				<xsl:value-of select="substring-before(concat(' ',normalize-space($other/@levels),' '),' - ')"/>
       
   288 				<xsl:value-of select="concat(' ',.,' ')"/>
       
   289 				<xsl:value-of select="substring-after(concat(' ',normalize-space($other/@levels),' '),' - ')"/>
       
   290 			</xsl:variable>
       
   291 			<xsl:attribute name="levels"><xsl:value-of select="normalize-space($lev)"/></xsl:attribute>
       
   292 		</xsl:when>
       
   293 		<xsl:otherwise> <!--  if they differ, use the origin's levels -->
       
   294 			<xsl:message>Note: levels differ "<xsl:value-of select="."/>" vs "<xsl:value-of select="$other/@levels"/>" on <xsl:value-of select="../@id"/></xsl:message>
       
   295 			<xsl:copy-of select="."/>
       
   296 		</xsl:otherwise>
       
   297 	</xsl:choose>
       
   298 </xsl:template>
       
   299 
       
   300 <xsl:template name="copy-sorted-content">
       
   301 	<xsl:param name="base"/>
       
   302 	<xsl:param name="to-sort"/>
       
   303 	<xsl:param name="start"/>
       
   304 	<xsl:param name="end"/>
       
   305 	<xsl:param name="down"/>
       
   306 	<xsl:param name="remainder" select="/.."/>
       
   307 
       
   308 	<xsl:choose>
       
   309 		<xsl:when test="not($to-sort)"/>  <!-- nothing left to copy. stop -->
       
   310 		<xsl:when test="not($base)"/>  <!-- reached end. stop -->
       
   311 		<xsl:otherwise>
       
   312 			<xsl:for-each select="$to-sort">
       
   313 				<xsl:if test="((@before=$end/@id) or not(@before) or not($base/ancestor::SystemDefinition//*[@id=current()/@before])) and not($base[@id=current()/@id])">
       
   314 					<xsl:apply-templates mode="merge-copy-of" select=".">
       
   315 						<xsl:with-param name="origin" select="$down"/>
       
   316 						<xsl:with-param name="root" select="$end/ancestor::SystemDefinition"/>
       
   317 					</xsl:apply-templates>
       
   318 				</xsl:if>
       
   319 			</xsl:for-each>
       
   320 		</xsl:otherwise>	
       
   321 	</xsl:choose>
       
   322 </xsl:template>
       
   323 
       
   324 <xsl:template match="node()" mode="merge-data">
       
   325 	<xsl:copy-of select="." />
       
   326 </xsl:template>
       
   327 
       
   328 <xsl:template match="meta" mode="merge-data">
       
   329 	<xsl:param name="metas" />
       
   330 	<!-- compare this meta against all metas in the  merged doc
       
   331 		if they are identical, then ignore this one.
       
   332 		identical is computed by translating to a string, normalising some known parts. This might be slow in some cases-->
       
   333 	<xsl:variable name="val"><xsl:apply-templates select="." mode="as-xml-text" /></xsl:variable>
       
   334 	<xsl:variable name="match">
       
   335 		<xsl:for-each select="$metas">
       
   336 			<xsl:variable name="cur"><xsl:apply-templates select="." mode="as-xml-text" /></xsl:variable>
       
   337 			<xsl:if test="$cur=$val">*</xsl:if>
       
   338 		</xsl:for-each>
       
   339 	</xsl:variable>
       
   340 	<xsl:if test="$match='' ">
       
   341 		<xsl:copy-of select="." />
       
   342 	</xsl:if>
       
   343 </xsl:template>
       
   344 
       
   345 <xsl:template match="text()[normalize-space(.)='']" mode="as-xml-text"/>
       
   346 <xsl:template match="node()" mode="as-xml-text"><xsl:value-of select="."/></xsl:template>
       
   347 <xsl:template match="comment()" mode="as-xml-text">&lt;--<xsl:value-of select="."/>--&gt;</xsl:template>
       
   348 <xsl:template match="@*" mode="as-xml-text">
       
   349 	<xsl:value-of select="concat(' ',name())"/>="<xsl:value-of select="."/>"</xsl:template>
       
   350 <xsl:template match="*" mode="as-xml-text">
       
   351 	<xsl:value-of select="concat('&lt;',name())"/>
       
   352 	<xsl:apply-templates select="@*" mode="as-xml-text"/>
       
   353 	<xsl:if test="self::meta and not(@rel)"> rel="Generic"</xsl:if>
       
   354 	<xsl:if test="self::meta and not(@type)"> type="auto"</xsl:if>
       
   355 	<xsl:text>&gt;</xsl:text>
       
   356 	<xsl:apply-templates select="node()" mode="as-xml-text"/>
       
   357 	<xsl:value-of select="concat('&lt;/',name(),'&gt;')"/>
       
   358 </xsl:template>
       
   359 
       
   360 
       
   361 <xsl:template name="best-prev"><xsl:param name="cur" select="."/><xsl:param name="alt"/>
       
   362 <xsl:if test="$alt">
       
   363 <xsl:variable name="prev" select="$cur/preceding-sibling::*[@id][1]"/> 
       
   364 <xsl:choose>
       
   365 	<xsl:when test="not($prev)"/>
       
   366 	<xsl:when test="$alt/preceding-sibling::*[@id=$prev/@id]"><xsl:value-of select="$prev/@id"/></xsl:when>
       
   367 	<xsl:otherwise>
       
   368 		<xsl:call-template name="best-prev">
       
   369 			<xsl:with-param name="cur" select="$prev"/>
       
   370 			<xsl:with-param name="alt" select="$alt"/>
       
   371 		</xsl:call-template>
       
   372 	</xsl:otherwise>
       
   373 </xsl:choose>
       
   374 </xsl:if>
       
   375 </xsl:template>
       
   376 
       
   377 <xsl:template match="layer | package | collection | component" mode="merge-models">
       
   378 	<xsl:param name="other"/>	<!-- the downstream item of the parent's rank that contains a potential items this is merged with -->
       
   379 	<xsl:param name="up"/>
       
   380 	<xsl:param name="down"/>
       
   381 	<xsl:param name="replaces"/>
       
   382 	<xsl:variable name="this" select="."/>	<!-- current item -->
       
   383 	<!-- match = this item in the downstream model -->	
       
   384 	<xsl:variable name="match" select="$other/*[@id=current()/@id]"/>
       
   385 
       
   386 	<xsl:choose>
       
   387 		<xsl:when test="$replaces[.=$this/@id] or (self::component and $match)">  <!-- replace the item instead of merge -->
       
   388 			<xsl:message>Note: <xsl:value-of select="name()"/> "<xsl:value-of select="@id"/>" in "<xsl:value-of select="../@id"/>" <xsl:choose>
       
   389 					<xsl:when test="self::component and $match">overridden in downstream sysdef</xsl:when>
       
   390 					<xsl:otherwise><xsl:for-each select="$replaces[.=$this/@id]/..">replaced by <xsl:value-of select="name()"/> "<xsl:value-of select="@id"/>" in "<xsl:value-of select="../@id"/>"</xsl:for-each></xsl:otherwise>
       
   391 				</xsl:choose>
       
   392 			</xsl:message>
       
   393 			<!-- if the removed item is in the downstream doc, just copy that and ignore the upstream contents -->
       
   394 			<xsl:apply-templates mode="merge-copy-of" select="$match">
       
   395 				<xsl:with-param name="origin" select="$down"/>
       
   396 				<xsl:with-param name="root" select="$this/ancestor::SystemDefinition"/>			
       
   397 				<xsl:with-param name="replaces" select="$replaces"/>
       
   398 			</xsl:apply-templates>		
       
   399 		</xsl:when>
       
   400 		<xsl:otherwise>
       
   401 			<!-- remove this if it's in the list of stuff to be replaced-->
       
   402 
       
   403 <xsl:variable name="prev-id">
       
   404 	<xsl:call-template name="best-prev">
       
   405 		<xsl:with-param name="alt" select="$match"/>
       
   406 	</xsl:call-template>
       
   407 </xsl:variable>
       
   408 
       
   409 
       
   410 	<!-- check the order of the items in the upstream and downstream doc. If they don't match up, we can't merge them nicely -->
       
   411 	<xsl:variable name="up-order">
       
   412 		<xsl:for-each select="../*[@id=$match/../*[not(@before)]/@id]"><xsl:value-of select="@id"/><xsl:text> </xsl:text></xsl:for-each>
       
   413 	</xsl:variable>
       
   414 	<xsl:variable name="down-order">
       
   415 		<xsl:for-each select="$match/../*[@id = current()/../*[not(@before)]/@id]"><xsl:value-of select="@id"/> <xsl:text> </xsl:text></xsl:for-each>
       
   416 	</xsl:variable>
       
   417 
       
   418 	<!-- prev = the previous item before the current one (no metas, only named items)-->
       
   419 	<xsl:variable name="prev" select="preceding-sibling::*[@id=$prev-id]"/> 
       
   420 
       
   421 
       
   422 	<!-- copy all items between this and prev that are solely in the downstream model -->	 		
       
   423 
       
   424 	<!-- <xsl:variable name="upstream-ids" select="ancestor::SystemDefinition//@id[parent::component or parent::collection or parent::package or parent::layer]"/> -->
       
   425 	<xsl:variable name="upstream-ids" select="../*/@id"/> <!-- this is much faster than using all IDs. before only currently works in the same parent anyway -->
       
   426 
       
   427 	<!-- $upstream-ids is used to avoid inserting an item that's being moved -->
       
   428 
       
   429 	<xsl:choose>
       
   430 		<xsl:when test="$match and $up-order != $down-order">
       
   431 		<!-- if the contents are in a different order, there's no way to merge them together. Don't try. Tack them on to the end later -->
       
   432 				<xsl:message>ERROR: Order of <xsl:value-of select="name()"/>s in upstream <xsl:value-of select="../@id"/>
       
   433 				<xsl:if test="not(../@id)">document</xsl:if> does not match the order of the <xsl:value-of select="name()"/>s in common in the downstream equivalent. Contents will not be properly merged: <xsl:value-of select="$up-order"/>  != 	<xsl:value-of select="$down-order"/></xsl:message>
       
   434 		</xsl:when>
       
   435 
       
   436 		<xsl:when test="$match and $prev">
       
   437 			<xsl:call-template name="copy-sorted-content">
       
   438 				<xsl:with-param name="base" select="../*[@id]"/>
       
   439 				<xsl:with-param name="to-sort" select="$other/*[@id and not(@before=$upstream-ids)][following-sibling::*[@id=$match/@id]][preceding-sibling::*[@id=$prev/@id]]"/>
       
   440 				<xsl:with-param name="start" select="$prev"/>
       
   441 				<xsl:with-param name="end" select="."/>
       
   442 				<xsl:with-param name="down" select="$down"/>
       
   443 			</xsl:call-template>
       
   444 		</xsl:when>
       
   445 		<xsl:when test="$match and not($prev)">
       
   446 			<xsl:call-template name="copy-sorted-content">
       
   447 				<xsl:with-param name="base" select="../*[@id]"/>
       
   448 				<xsl:with-param name="to-sort" select="$other/*[@id and not(@before=$upstream-ids)][following-sibling::*[@id=$match/@id]]"/>
       
   449 				<xsl:with-param name="start" select="$prev"/>
       
   450 				<xsl:with-param name="end" select="."/>
       
   451 				<xsl:with-param name="down" select="$down"/>
       
   452 			</xsl:call-template>
       
   453 		</xsl:when>
       
   454 	</xsl:choose>
       
   455 
       
   456  	<!-- just copy anything identified as being before this, assume they're all ok -->
       
   457 
       
   458 	<xsl:apply-templates mode="merge-copy-of" select="$other/*[@before=current()/@id]">
       
   459 		<xsl:with-param name="remove-before" select="1"/>
       
   460 		<xsl:with-param name="origin" select="$down"/>
       
   461 		<xsl:with-param name="root" select="$this/ancestor::SystemDefinition"/>	
       
   462 		<xsl:with-param name="replaces" select="$replaces"/>
       
   463 	</xsl:apply-templates>
       
   464 	
       
   465 	<xsl:copy>
       
   466 		<xsl:apply-templates select="@*" mode="merge-models"> <!-- copy upstream attributes -->
       
   467 			<xsl:with-param name="other" select="$match"/>
       
   468 		</xsl:apply-templates>
       
   469 		<xsl:if test="self::component and not(@origin-model) and ($up/@name or ancestor::systemModel/@name)">
       
   470 			<!-- insert origin-model and optional root for components only -->
       
   471 			<xsl:attribute name="origin-model">
       
   472 				<xsl:value-of select="$up/@name"/>
       
   473 				<xsl:if test="not($up/@name)"><xsl:value-of select="ancestor::systemModel/@name"/></xsl:if>
       
   474 			</xsl:attribute>
       
   475 			<xsl:if test="not(@root)">
       
   476 				<xsl:copy-of select="$up/@root"/>
       
   477 			</xsl:if>
       
   478 		</xsl:if>
       
   479 		
       
   480 		<xsl:for-each select="$match/@*[name()!='replace']">  <!-- copy downstream attributes, only if not set on upstream -->
       
   481 			<xsl:if test="not($this/@*[name()=name(current())])"><xsl:copy-of select="."/></xsl:if>
       
   482 		</xsl:for-each>
       
   483 
       
   484 		<xsl:if test="$match/@replace"> <!-- check replace separately -->
       
   485 			<xsl:if test="not($this/ancestor::SystemDefinition//*[(self::component or self::collection or self::package or self::layer) and $match/@replace=@id])">
       
   486 				<!-- only remove replace if it's been used -->
       
   487 				<xsl:copy-of select="$match/@replace"/>
       
   488 			</xsl:if>
       
   489 		</xsl:if>
       
   490 		
       
   491 		<xsl:choose>
       
   492 			<xsl:when test="self::component">
       
   493 				<!-- copy all units, metas and comments from this
       
   494 					copy all metas in the merged component
       
   495 					copy any new comments in the merged component (not duplicates)
       
   496 					if there are no units in the this, copy all units in the merged component
       
   497 					if there are units in this, copy only the versioned units in the merged component (only those versions not already specified) -->
       
   498 				<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()]"/>				
       
   499 			</xsl:when>
       
   500 			<xsl:otherwise>
       
   501 
       
   502 				<!--  copy metas and comments in between meta. Do not try to merge metadata between models -->
       
   503 				<xsl:apply-templates select="meta | $match/meta | comment()[following-sibling::meta]" mode="merge-data">
       
   504 					<xsl:with-param name="metas" select="$match/meta"/>
       
   505 				</xsl:apply-templates>
       
   506 				<xsl:copy-of select=" $match/meta | $match/comment()[following-sibling::meta]"/>
       
   507 				
       
   508 				<xsl:apply-templates mode="merge-models">
       
   509 					<xsl:with-param name="other" select="$match"/>
       
   510 					<xsl:with-param name="up" select="$up"/>
       
   511 					<xsl:with-param name="down" select="$down"/>
       
   512 					<xsl:with-param name="replaces" select="$replaces"/>
       
   513 				</xsl:apply-templates>
       
   514 				<!--  don't copy if explicitly or implicitly placed already-->
       
   515 				<xsl:for-each select="$match/*[not(@before) and not(following-sibling::*[@id=$this/*/@id])]">
       
   516 					<xsl:if test="not($this/*[@id=current()/@id])">
       
   517 						<xsl:apply-templates mode="merge-copy-of" select=".">
       
   518 							<xsl:with-param name="origin" select="$down"/>
       
   519 							<xsl:with-param name="root" select="$this/ancestor::SystemDefinition"/>			
       
   520 							<xsl:with-param name="replaces" select="$replaces"/>
       
   521 						</xsl:apply-templates>
       
   522 					</xsl:if>
       
   523 				</xsl:for-each>
       
   524 			</xsl:otherwise>
       
   525 		</xsl:choose>
       
   526 
       
   527 		<!-- and now check for error cases, and tack those on -->
       
   528 		<xsl:call-template name="check-and-add-out-of-order-items">
       
   529 			<xsl:with-param name="match" select="$match"/>
       
   530 			<xsl:with-param name="down" select="$down"/>
       
   531 			<xsl:with-param name="replaces" select="$replaces"/>
       
   532 		</xsl:call-template> 
       
   533 
       
   534 	</xsl:copy>
       
   535  	</xsl:otherwise>
       
   536 	</xsl:choose>
       
   537 </xsl:template>
       
   538 
       
   539 
       
   540 
       
   541 <xsl:template match="*" mode="merge-copy-of">
       
   542 	<xsl:param name="remove-before" select="0"/> <!-- set to true if any before attribute is to be removed -->
       
   543 	<xsl:param name="origin"/>	<!--the element containing the @name to use the origin-model attribute  -->
       
   544 	<xsl:param name="root"/> 	<!--the systemModel element in the upstream doc  -->
       
   545 	<xsl:param name="replaces" select="ancestor::SystemDefinition/descendant::*[(self::component or self::collection or self::package or self::layer) and not(ancestor::meta)]/@replace"/> <!-- recalculate this is necessarfy, but should just pass down as a param -->
       
   546 	<xsl:variable name="moved" select="$root/descendant::*[name()=name(current()/..) and @id!=current()/../@id]/*[@id=current()/@id]"/>
       
   547 	<xsl:choose>
       
   548 		<!-- this might slow things down, consider making optional -->
       
   549 		<xsl:when test="not(self::layer) and (count($moved) and not($moved[ancestor-or-self::*/@id=$replaces]) )">
       
   550 			<xsl:message>Warning: <xsl:value-of select="name()"/> "<xsl:value-of select="@id"/>" moved in downstream model. Ignoring moved <xsl:value-of select="name()"/>
       
   551 				<xsl:text>&#xa;</xsl:text>
       
   552 			</xsl:message>
       
   553 		</xsl:when>
       
   554 		<xsl:otherwise>
       
   555 			<!-- save all content in a variable to test to see if it's got any problems (ie been removed due to errors)-->
       
   556 			<xsl:variable name="content">
       
   557 				<xsl:apply-templates select="*|comment()" mode="merge-copy-of">
       
   558 					<xsl:with-param name="origin" select="$origin"/>
       
   559 					<xsl:with-param name="root" select="$root"/>
       
   560 					<xsl:with-param name="replaces" select="$replaces"/>
       
   561 				</xsl:apply-templates>
       
   562 			</xsl:variable>
       
   563 			<xsl:choose>
       
   564 				<!-- if all elements in this have been deleted, throw out this element -->
       
   565 				<xsl:when test="not(exslt:node-set($content)/*) and *">
       
   566 					<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()"/>
       
   567 						<xsl:text>&#xa;</xsl:text>
       
   568 					</xsl:message>
       
   569 				</xsl:when>
       
   570 				<xsl:otherwise>
       
   571 					<xsl:copy>
       
   572 						<xsl:call-template name="merge-copy-of-atts">
       
   573 							<xsl:with-param name="remove-before" select="$remove-before"/>
       
   574 							<xsl:with-param name="root" select="$root"/>
       
   575 						</xsl:call-template>
       
   576 						<xsl:copy-of select="exslt:node-set($content)"/>
       
   577 					</xsl:copy>
       
   578 				</xsl:otherwise>
       
   579 			</xsl:choose>					
       
   580 		</xsl:otherwise>
       
   581 	</xsl:choose>
       
   582 </xsl:template>
       
   583 <xsl:template match="comment()|@*" mode="merge-copy-of">
       
   584 	<xsl:copy-of select="."/>
       
   585 </xsl:template>
       
   586 
       
   587 
       
   588 <xsl:template name="merge-copy-of-atts">
       
   589 	<xsl:param name="remove-before" select="0"/> <!-- set to true if any before attribute is to be removed -->
       
   590 	<xsl:param name="root"/> 	<!--the systemModel element in the upstream doc  -->
       
   591 	
       
   592 	<xsl:choose>
       
   593 		<xsl:when test="$remove-before">
       
   594 			<xsl:copy-of select="@*[name()!='before' and name()!='replace']"/>
       
   595 		</xsl:when>
       
   596 		<xsl:otherwise><xsl:copy-of select="@*[name()!='replace']"/></xsl:otherwise>
       
   597 	</xsl:choose>
       
   598 	<xsl:if test="@replace and not($root/descendant::*[(self::component or self::collection or self::package or self::layer) and @id=current()/@replace])">
       
   599 		<!-- only include replace if it's not been used -->
       
   600 		<xsl:copy-of select="@replace"/>
       
   601 	</xsl:if>
       
   602 </xsl:template>
       
   603 
       
   604 <xsl:template match="component" mode="merge-copy-of">
       
   605 	<xsl:param name="remove-before" select="0"/> <!-- set to true if any before attribute is to be removed -->
       
   606 	<xsl:param name="origin"/>	<!--the element containing the @name to use the origin-model attribute  -->
       
   607 	<xsl:param name="root"/> 	<!--the systemModel element in the upstream doc  -->
       
   608 	<xsl:choose>
       
   609 		<!-- this might slow things down, consider making optional -->
       
   610 		<xsl:when test="$root/descendant::collection[@id!=current()/../@id]/component[@id=current()/@id]">
       
   611 			<xsl:message>Warning: <xsl:value-of select="name()"/> "<xsl:value-of select="@id"/>" moved in downstream model. Ignoring moved <xsl:value-of select="name()"/>
       
   612 				<xsl:text>&#xa;</xsl:text>
       
   613 			</xsl:message>
       
   614 		</xsl:when>
       
   615 		<xsl:otherwise>
       
   616 			<xsl:copy>
       
   617 				<xsl:call-template name="merge-copy-of-atts">
       
   618 					<xsl:with-param name="remove-before" select="$remove-before"/>
       
   619 					<xsl:with-param name="root" select="$root"/>
       
   620 				</xsl:call-template>
       
   621 				<xsl:if test="not(@origin-model) and ($origin/@name or ancestor::systemModel/@name)">
       
   622 					<xsl:attribute name="origin-model">
       
   623 						<xsl:value-of select="$origin/@name"/>
       
   624 						<xsl:if test="not($origin/@name)"><xsl:value-of select="ancestor::systemModel/@name"/></xsl:if>
       
   625 					</xsl:attribute>
       
   626 					<xsl:if test="not(@root)">
       
   627 						<xsl:copy-of select="$origin/@root"/>
       
   628 					</xsl:if>
       
   629 				</xsl:if>
       
   630 				<xsl:apply-templates select="*|comment()" mode="merge-copy-of">
       
   631 					<xsl:with-param name="origin" select="$origin"/>
       
   632 					<xsl:with-param name="root" select="$root"/>
       
   633 				</xsl:apply-templates>
       
   634 			</xsl:copy>
       
   635 		</xsl:otherwise>
       
   636 	</xsl:choose>
       
   637 </xsl:template>
       
   638 
       
   639 
       
   640 <xsl:template match="unit" mode="merge-copy-of">
       
   641 	<xsl:param name="origin"/>	<!--the element containing the @name to use the origin-model attribute  -->
       
   642 	<xsl:param name="root"/> 	<!--the systemModel element in the upstream doc  -->
       
   643 	<xsl:copy>
       
   644 				<xsl:apply-templates select="@*" mode="merge-copy-of">
       
   645 					<xsl:with-param name="origin" select="$origin"/>
       
   646 					<xsl:with-param name="root" select="$root"/>
       
   647 				</xsl:apply-templates>
       
   648 	</xsl:copy>
       
   649 </xsl:template>
       
   650 
       
   651 
       
   652 
       
   653 
       
   654 <xsl:template match="meta" mode="merge-copy-of">
       
   655 	<xsl:param name="origin"/>	<!--the element containing the @name to use the origin-model attribute  -->
       
   656 	<xsl:param name="root"/> 	<!--the systemModel element in the upstream doc  -->
       
   657 	<xsl:copy>
       
   658 		<xsl:apply-templates select="@*" mode="merge-copy-of">
       
   659 			<xsl:with-param name="origin" select="$origin"/>
       
   660 			<xsl:with-param name="root" select="$root"/>
       
   661 		</xsl:apply-templates>
       
   662 		<xsl:copy-of select="node()"/>
       
   663 	</xsl:copy>
       
   664 </xsl:template>
       
   665 
       
   666 
       
   667 <xsl:template match="unit/@bldFile | unit/@mrp | unit/@base | meta/@href" mode="merge-copy-of">
       
   668 	<xsl:param name="origin" select="/.."/>	<!--the element containing the @name to use the origin-model attribute  -->
       
   669 
       
   670 	<xsl:attribute name="{name()}">
       
   671 		<xsl:choose>
       
   672 			<xsl:when test="not($origin/@pathto)"><xsl:value-of select="."/></xsl:when>
       
   673 			<xsl:when test="(contains(.,'://') and not(contains(substring-before(.,'://'),'/'))) or starts-with(.,'/')"> <!-- absolute URI or absolute path-->
       
   674 				<xsl:value-of select="."/>
       
   675 			</xsl:when>
       
   676 			<xsl:when test="contains($origin/@pathto,'://') and not(contains(substring-before($origin/@pathto,'://'),'/'))"> <!-- absolute URI for downstream sysdef not valif for unit paths, just copy and raise warning-->
       
   677 				<xsl:message>ERROR: Could not resolve relative path in downstream file: <xsl:value-of select="."/> relative to absolute URI <xsl:value-of select="$origin/@pathto"/></xsl:message>
       
   678 				<xsl:value-of select="."/>
       
   679 			</xsl:when>
       
   680 		<xsl:otherwise> <!-- relative link -->
       
   681 			<xsl:call-template name="joinpath">
       
   682 				<xsl:with-param name="file" select="$origin/@pathto"/>
       
   683 				<xsl:with-param name="rel" select="."/>
       
   684 			</xsl:call-template>
       
   685 		</xsl:otherwise>
       
   686 		</xsl:choose>
       
   687 	</xsl:attribute>
       
   688 </xsl:template>
       
   689 </xsl:stylesheet>