metatools/sysdeftools/lib/mergesysdef-module.xsl
changeset 624 f70b728ea30c
child 636 29e6a24e9521
equal deleted inserted replaced
621:96fee2635b19 624:f70b728ea30c
       
     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 converetd 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 	</xsl:copy>
       
   216 </xsl:template>
       
   217 
       
   218 <xsl:template match="@*|*|comment()" mode="merge-models"><xsl:copy-of select="."/></xsl:template>
       
   219 
       
   220 
       
   221 <xsl:template match="meta|comment()[following-sibling::meta]" mode="merge-models"/>
       
   222 	<!-- copy elesewhere, not here so that metas always appear first-->
       
   223 
       
   224 
       
   225 
       
   226 <!-- merge levels attribute via std rules -->
       
   227 <xsl:template match="layer/@levels|package/@levels" mode="merge-models">
       
   228 	<xsl:param name="other"/><!-- the element contains the other @levels -->
       
   229 	<xsl:choose>
       
   230 		<!--  if they are the same, or not specified in the other,  just copy -->
       
   231 		<xsl:when test=".=$other/@levels or not($other/@levels)"><xsl:copy-of select="."/></xsl:when>
       
   232 		<xsl:when test="contains(concat(' ',normalize-space(.),' '),concat(' ',normalize-space($other/@levels),' '))">
       
   233 			<!--upstream completely contains downstream, just copy --> 
       
   234 			<xsl:copy-of select="."/>
       
   235 		</xsl:when>
       
   236 		<xsl:when test="contains(concat(' ',normalize-space($other/@levels),' '),concat(' ',normalize-space(.),' '))">
       
   237 			<!--  If this is contained is other, then use other-->
       
   238 			<xsl:copy-of select="$other/@levels"/>
       
   239 		</xsl:when>
       
   240 		<xsl:when test="contains(concat(' ',normalize-space($other/@levels),' '),' - ')">
       
   241 			<!-- if other uses - syntax, then pre/append -->
       
   242 			<xsl:variable name="lev">
       
   243 				<xsl:value-of select="substring-before(concat(' ',normalize-space($other/@levels),' '),' - ')"/>
       
   244 				<xsl:value-of select="concat(' ',.,' ')"/>
       
   245 				<xsl:value-of select="substring-after(concat(' ',normalize-space($other/@levels),' '),' - ')"/>
       
   246 			</xsl:variable>
       
   247 			<xsl:attribute name="levels"><xsl:value-of select="normalize-space($lev)"/></xsl:attribute>
       
   248 		</xsl:when>
       
   249 		<xsl:otherwise> <!--  if they differ, use the origin's levels -->
       
   250 			<xsl:message>Note: levels differ "<xsl:value-of select="."/>" vs "<xsl:value-of select="$other/@levels"/>" on <xsl:value-of select="../@id"/></xsl:message>
       
   251 			<xsl:copy-of select="."/>
       
   252 		</xsl:otherwise>
       
   253 	</xsl:choose>
       
   254 </xsl:template>
       
   255 
       
   256 <xsl:template name="copy-sorted-content">
       
   257 	<xsl:param name="base"/>
       
   258 	<xsl:param name="to-sort"/>
       
   259 	<xsl:param name="start"/>
       
   260 	<xsl:param name="end"/>
       
   261 	<xsl:param name="down"/>
       
   262 	<xsl:param name="remainder" select="/.."/>
       
   263 
       
   264 	<xsl:choose>
       
   265 		<xsl:when test="not($to-sort)"/>  <!-- nothing left to copy. stop -->
       
   266 		<xsl:when test="not($base)"/>  <!-- reached end. stop -->
       
   267 		<xsl:when test="$base[1]/@id=$end/following-sibling::*[1]/@id"/> <!-- passed $end. Stop -->
       
   268 		<xsl:when test="$base[1]/@id = $to-sort[1]/@id">  <!-- both lists start with same item -->
       
   269 			<xsl:if test="$base[1]/@id!=$end/@id"> <!-- not at end, so keep going -->
       
   270 				<xsl:call-template name="copy-sorted-content">
       
   271 					<xsl:with-param name="base" select="$base[position() != 1]"/>
       
   272 					<xsl:with-param name="to-sort" select="$to-sort[position() != 1]"/>
       
   273 					<xsl:with-param name="remainder" select="$remainder"/>
       
   274 					<xsl:with-param name="start" select="$start"/>
       
   275 					<xsl:with-param name="end" select="$end"/>
       
   276 					<xsl:with-param name="down" select="$down"/>
       
   277 				</xsl:call-template>		
       
   278 			</xsl:if>
       
   279 		</xsl:when>	
       
   280 		<xsl:when test="$remainder[@id = $base[1]/@id]"> <!-- left over item is in $base -->
       
   281 			<xsl:call-template name="copy-sorted-content">
       
   282 				<xsl:with-param name="base" select="$base[position() != 1]"/>
       
   283 				<xsl:with-param name="to-sort" select="$to-sort"/>
       
   284 				<xsl:with-param name="remainder" select="$remainder[@id != $base[1]/@id]"/>
       
   285 				<xsl:with-param name="start" select="$start"/>
       
   286 				<xsl:with-param name="end" select="$end"/>
       
   287 				<xsl:with-param name="down" select="$down"/>
       
   288 			</xsl:call-template>		
       
   289 		</xsl:when>
       
   290 		<xsl:when test="not($base[@id = $to-sort[1]/@id])"> <!-- in to-sort, but not base -->		
       
   291 			<xsl:if test="$base[1]/@id=$end/@id  and not($base[@id=$to-sort[1]/@before])">
       
   292 			 	<!-- if at end, then this needs to be copied
       
   293 					don't copy if the before ID is found in $base	-->
       
   294 				<xsl:apply-templates mode="merge-copy-of" select="$to-sort[1]">
       
   295 					<xsl:with-param name="origin" select="$down"/>
       
   296 					<xsl:with-param name="root" select="$end/ancestor::SystemDefinition"/>
       
   297 				</xsl:apply-templates>
       
   298 			</xsl:if>			
       
   299 		<xsl:call-template name="copy-sorted-content">
       
   300 			<xsl:with-param name="base" select="$base"/>
       
   301 			<xsl:with-param name="to-sort" select="$to-sort[position() != 1]"/>
       
   302 			<xsl:with-param name="remainder" select="$remainder"/>
       
   303 			<xsl:with-param name="start" select="$start"/>
       
   304 			<xsl:with-param name="end" select="$end"/>
       
   305 			<xsl:with-param name="down" select="$down"/>
       
   306 		</xsl:call-template>		
       
   307 		</xsl:when>	
       
   308 		<xsl:when test="not($to-sort[@id = $base[1]/@id])"> <!-- in base, but not to-sort -->		
       
   309 		<xsl:call-template name="copy-sorted-content">
       
   310 			<xsl:with-param name="base" select="$base[position() != 1]"/>
       
   311 			<xsl:with-param name="to-sort" select="$to-sort"/>
       
   312 			<xsl:with-param name="remainder" select="$remainder"/>
       
   313 			<xsl:with-param name="start" select="$start"/>
       
   314 			<xsl:with-param name="end" select="$end"/>
       
   315 			<xsl:with-param name="down" select="$down"/>
       
   316 		</xsl:call-template>		
       
   317 		</xsl:when>	
       
   318 		<xsl:when test="$base[@id = $to-sort[1]/@id]"> <!-- is in base, but not 1st one-->
       
   319 			<xsl:call-template name="copy-sorted-content">
       
   320 				<xsl:with-param name="base" select="$base"/>
       
   321 				<xsl:with-param name="to-sort" select="$to-sort[position() != 1] "/>
       
   322 				<xsl:with-param name="remainder" select="$remainder | $to-sort[1]"/>
       
   323 				<xsl:with-param name="start" select="$start"/>
       
   324 				<xsl:with-param name="end" select="$end"/>
       
   325 				<xsl:with-param name="down" select="$down"/>
       
   326 			</xsl:call-template>
       
   327 		</xsl:when>	
       
   328 	</xsl:choose>
       
   329 </xsl:template>
       
   330 
       
   331 <xsl:template match="node()" mode="merge-data">
       
   332 	<xsl:copy-of select="." />
       
   333 </xsl:template>
       
   334 
       
   335 <xsl:template match="meta" mode="merge-data">
       
   336 	<xsl:param name="metas" />
       
   337 	<!-- compare this meta against all metas in the  merged doc
       
   338 		if they are identical, then ignore this one.
       
   339 		identical is computed by translating to a string, normalising some known parts. This might be slow in some cases-->
       
   340 	<xsl:variable name="val"><xsl:apply-templates select="." mode="as-xml-text" /></xsl:variable>
       
   341 	<xsl:variable name="match">
       
   342 		<xsl:for-each select="$metas">
       
   343 			<xsl:variable name="cur"><xsl:apply-templates select="." mode="as-xml-text" /></xsl:variable>
       
   344 			<xsl:if test="$cur=$val">*</xsl:if>
       
   345 		</xsl:for-each>
       
   346 	</xsl:variable>
       
   347 	<xsl:if test="$match='' ">
       
   348 		<xsl:copy-of select="." />
       
   349 	</xsl:if>
       
   350 </xsl:template>
       
   351 
       
   352 <xsl:template match="text()[normalize-space(.)='']" mode="as-xml-text"/>
       
   353 <xsl:template match="node()" mode="as-xml-text"><xsl:value-of select="."/></xsl:template>
       
   354 <xsl:template match="comment()" mode="as-xml-text">&lt;--<xsl:value-of select="."/>--&gt;</xsl:template>
       
   355 <xsl:template match="@*" mode="as-xml-text">
       
   356 	<xsl:value-of select="concat(' ',name())"/>="<xsl:value-of select="."/>"</xsl:template>
       
   357 <xsl:template match="*" mode="as-xml-text">
       
   358 	<xsl:value-of select="concat('&lt;',name())"/>
       
   359 	<xsl:apply-templates select="@*" mode="as-xml-text"/>
       
   360 	<xsl:if test="self::meta and not(@rel)"> rel="Generic"</xsl:if>
       
   361 	<xsl:if test="self::meta and not(@type)"> type="auto"</xsl:if>
       
   362 	<xsl:text>&gt;</xsl:text>
       
   363 	<xsl:apply-templates select="node()" mode="as-xml-text"/>
       
   364 	<xsl:value-of select="concat('&lt;/',name(),'&gt;')"/>
       
   365 </xsl:template>
       
   366 
       
   367 
       
   368 <xsl:template match="layer | package | collection | component" mode="merge-models">
       
   369 	<xsl:param name="other"/>	<!-- the downstream item of the parent's rank that contains a potential items this is merged with -->
       
   370 	<xsl:param name="up"/>
       
   371 	<xsl:param name="down"/>
       
   372 	<xsl:param name="replaces"/>
       
   373 	<xsl:variable name="this" select="."/>	<!-- current item -->
       
   374 	<!-- match = this item in the downstream model -->	
       
   375 	<xsl:variable name="match" select="$other/*[@id=current()/@id]"/>
       
   376 
       
   377 	<xsl:choose>
       
   378 		<xsl:when test="$replaces[.=$this/@id] or (self::component and $match)">  <!-- replace the item instead of merge -->
       
   379 			<xsl:message>Note: <xsl:value-of select="name()"/> "<xsl:value-of select="@id"/>" in "<xsl:value-of select="../@id"/>" <xsl:choose>
       
   380 				<xsl:when test="self::component and $match">overridden in downstream sysdef</xsl:when>
       
   381 				<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>
       
   382 			</xsl:choose>
       
   383 			</xsl:message>
       
   384 			<!-- if the removed item is in the downstream doc, just copy that and ignore the upstream contents -->
       
   385 			<xsl:apply-templates mode="merge-copy-of" select="$match">
       
   386 				<xsl:with-param name="origin" select="$down"/>
       
   387 				<xsl:with-param name="root" select="$this/ancestor::SystemDefinition"/>			
       
   388 				<xsl:with-param name="replaces" select="$replaces"/>
       
   389 			</xsl:apply-templates>		
       
   390 		</xsl:when>
       
   391 		<xsl:otherwise>
       
   392 			<!-- remove this if it's in the list of stuff to be replaced-->
       
   393 
       
   394 	<!-- prev = the previous item before the current one (no metas, only named items)-->
       
   395 	<xsl:variable name="prev" select="preceding-sibling::*[@id][1]"/> 
       
   396 
       
   397 	<!-- copy all items between this and prev  that are solely in the downstream model -->	 		
       
   398 
       
   399 	<xsl:choose>
       
   400 		<xsl:when test="$match and (not($prev) or $other/*[@id= $prev/@id] )">
       
   401 			<xsl:call-template name="copy-sorted-content">
       
   402 				<xsl:with-param name="base" select="../*[@id]"/>
       
   403 				<xsl:with-param name="to-sort" select="$other/*[@id]"/>
       
   404 				<xsl:with-param name="start" select="$prev"/>
       
   405 				<xsl:with-param name="end" select="."/>
       
   406 				<xsl:with-param name="down" select="$down"/>
       
   407 			</xsl:call-template>
       
   408 		</xsl:when>
       
   409 	<xsl:when test="not($match/preceding-sibling::*[@id=$this/../*/@id]) and $other/*[@id= current()/@id]/preceding-sibling::*[@id and not(@before)]">
       
   410 		<!-- if this is the first item in other that's also in this, then put all new items from other here -->
       
   411 		<xsl:apply-templates mode="merge-copy-of" select="$match/preceding-sibling::*[@id and not(@before)]">
       
   412 			<xsl:with-param name="origin" select="$down"/>
       
   413 			<xsl:with-param name="root" select="$this/ancestor::SystemDefinition"/>	
       
   414 			<xsl:with-param name="replaces" select="$replaces"/>
       
   415 		</xsl:apply-templates>
       
   416 	</xsl:when>
       
   417 	</xsl:choose>
       
   418 
       
   419  	<!-- just copy anything identified as being before this, assume they're all ok -->
       
   420 	<xsl:apply-templates mode="merge-copy-of" select="$other/*[@before=current()/@id]">
       
   421 		<xsl:with-param name="remove-before" select="1"/>
       
   422 		<xsl:with-param name="origin" select="$down"/>
       
   423 		<xsl:with-param name="root" select="$this/ancestor::SystemDefinition"/>	
       
   424 		<xsl:with-param name="replaces" select="$replaces"/>
       
   425 	</xsl:apply-templates>
       
   426 
       
   427 	
       
   428 	<xsl:copy>
       
   429 		<xsl:apply-templates select="@*" mode="merge-models"> <!-- copy upstream attributes -->
       
   430 			<xsl:with-param name="other" select="$match"/>
       
   431 		</xsl:apply-templates>
       
   432 		
       
   433 		<xsl:if test="self::component and not(@origin-model) and $up/@name">
       
   434 			<!-- insert origin-model and optional root for components only -->
       
   435 			<xsl:attribute name="origin-model">
       
   436 				<xsl:value-of select="$up/@name"/>
       
   437 			</xsl:attribute>
       
   438 			<xsl:if test="not(@root)">
       
   439 				<xsl:copy-of select="$up/@root"/>
       
   440 			</xsl:if>
       
   441 		</xsl:if>
       
   442 		
       
   443 		<xsl:for-each select="$match/@*[name()!='replace']">  <!-- copy downstream attributes, only if not set on upstream -->
       
   444 			<xsl:if test="not($this/@*[name()=name(current())])"><xsl:copy-of select="."/></xsl:if>
       
   445 		</xsl:for-each>
       
   446 
       
   447 		<xsl:if test="$match/@replace"> <!-- check replace separately -->
       
   448 			<xsl:if test="not($this/ancestor::SystemDefinition//*[(self::component or self::collection or self::package or self::layer) and $match/@replace=@id])">
       
   449 				<!-- only remove replace if it's been used -->
       
   450 				<xsl:copy-of select="$match/@replace"/>
       
   451 			</xsl:if>
       
   452 		</xsl:if>
       
   453 		
       
   454 		<xsl:choose>
       
   455 			<xsl:when test="self::component">
       
   456 				<!-- copy all units, metas and comments from this
       
   457 					copy all metas in the merged component
       
   458 					copy any new comments in the merged component (not duplicates)
       
   459 					if there are no units in the this, copy all units in the merged component
       
   460 					if there are units in this, copy only the versioned units in the merged component (only those versions not already specified) -->
       
   461 				<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()]"/>				
       
   462 			</xsl:when>
       
   463 			<xsl:otherwise>
       
   464 
       
   465 				<!--  copy metas and comments in between meta. Do not try to merge metadata between models -->
       
   466 				<xsl:apply-templates select="meta | $match/meta | comment()[following-sibling::meta]" mode="merge-data">
       
   467 					<xsl:with-param name="metas" select="$match/meta"/>
       
   468 				</xsl:apply-templates>
       
   469 				<xsl:copy-of select=" $match/meta | $match/comment()[following-sibling::meta]"/>
       
   470 				
       
   471 				<xsl:apply-templates mode="merge-models">
       
   472 					<xsl:with-param name="other" select="$match"/>
       
   473 					<xsl:with-param name="up" select="$up"/>
       
   474 					<xsl:with-param name="down" select="$down"/>
       
   475 					<xsl:with-param name="replaces" select="$replaces"/>
       
   476 				</xsl:apply-templates>
       
   477 				<!--  don't copy if explicitly or implicitly placed already-->
       
   478 				<xsl:for-each select="$match/*[not(@before) and not(following-sibling::*[@id=$this/*/@id])]">
       
   479 					<xsl:if test="not($this/*[@id=current()/@id])">
       
   480 						<xsl:apply-templates mode="merge-copy-of" select=".">
       
   481 							<xsl:with-param name="origin" select="$down"/>
       
   482 							<xsl:with-param name="root" select="$this/ancestor::SystemDefinition"/>			
       
   483 							<xsl:with-param name="replaces" select="$replaces"/>
       
   484 						</xsl:apply-templates>
       
   485 					</xsl:if>
       
   486 				</xsl:for-each>
       
   487 			</xsl:otherwise>
       
   488 		</xsl:choose>
       
   489 	</xsl:copy>
       
   490 
       
   491 		</xsl:otherwise>
       
   492 	</xsl:choose>
       
   493 	
       
   494 	<xsl:if test="self::layer and not(following-sibling::layer)">	
       
   495 		<!-- for the last layer, tack on any remaining layers -->
       
   496 		<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)]">
       
   497 			<xsl:with-param name="origin" select="$down"/>
       
   498 			<xsl:with-param name="root" select="$this/ancestor::SystemDefinition"/>			
       
   499 			<xsl:with-param name="replaces" select="$replaces"/>
       
   500 		</xsl:apply-templates>		
       
   501 	</xsl:if>
       
   502 </xsl:template>
       
   503 
       
   504 
       
   505 
       
   506 <xsl:template match="*" mode="merge-copy-of">
       
   507 	<xsl:param name="remove-before" select="0"/> <!-- set to true if any before attribute is to be removed -->
       
   508 	<xsl:param name="origin"/>	<!--the element containing the @name to use the origin-model attribute  -->
       
   509 	<xsl:param name="root"/> 	<!--the systemModel element in the upstream doc  -->
       
   510 	<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 -->
       
   511 	<xsl:variable name="moved" select="$root/descendant::*[name()=name(current()/..) and @id!=current()/../@id]/*[@id=current()/@id]"/>
       
   512 	<xsl:choose>
       
   513 		<!-- this might slow things down, consider making optional -->
       
   514 		<xsl:when test="not(self::layer) and (count($moved) and not($moved[ancestor-or-self::*/@id=$replaces]) )">
       
   515 			<xsl:message>Warning: <xsl:value-of select="name()"/> "<xsl:value-of select="@id"/>" moved in downstream model. Ignoring moved <xsl:value-of select="name()"/>
       
   516 				<xsl:text>&#xa;</xsl:text>
       
   517 			</xsl:message>
       
   518 		</xsl:when>
       
   519 		<xsl:otherwise>
       
   520 			<!-- save all content in a variable to test to see if it's got any problems (ie been removed due to errors)-->
       
   521 			<xsl:variable name="content">
       
   522 				<xsl:apply-templates select="*|comment()" mode="merge-copy-of">
       
   523 					<xsl:with-param name="origin" select="$origin"/>
       
   524 					<xsl:with-param name="root" select="$root"/>
       
   525 					<xsl:with-param name="replaces" select="$replaces"/>
       
   526 				</xsl:apply-templates>
       
   527 			</xsl:variable>
       
   528 			<xsl:choose>
       
   529 				<!-- if all elements in this have been deleted, throw out this element -->
       
   530 				<xsl:when test="not(exslt:node-set($content)/*) and *">
       
   531 					<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()"/>
       
   532 						<xsl:text>&#xa;</xsl:text>
       
   533 					</xsl:message>
       
   534 				</xsl:when>
       
   535 				<xsl:otherwise>
       
   536 					<xsl:copy>
       
   537 						<xsl:call-template name="merge-copy-of-atts">
       
   538 							<xsl:with-param name="remove-before" select="$remove-before"/>
       
   539 							<xsl:with-param name="root" select="$root"/>
       
   540 						</xsl:call-template>
       
   541 						<xsl:copy-of select="exslt:node-set($content)"/>
       
   542 					</xsl:copy>
       
   543 				</xsl:otherwise>
       
   544 			</xsl:choose>					
       
   545 		</xsl:otherwise>
       
   546 	</xsl:choose>
       
   547 </xsl:template>
       
   548 <xsl:template match="comment()|@*" mode="merge-copy-of">
       
   549 	<xsl:copy-of select="."/>
       
   550 </xsl:template>
       
   551 
       
   552 
       
   553 <xsl:template name="merge-copy-of-atts">
       
   554 	<xsl:param name="remove-before" select="0"/> <!-- set to true if any before attribute is to be removed -->
       
   555 	<xsl:param name="root"/> 	<!--the systemModel element in the upstream doc  -->
       
   556 	
       
   557 	<xsl:choose>
       
   558 		<xsl:when test="$remove-before">
       
   559 			<xsl:copy-of select="@*[name()!='before' and name()!='replace']"/>
       
   560 		</xsl:when>
       
   561 		<xsl:otherwise><xsl:copy-of select="@*[name()!='replace']"/></xsl:otherwise>
       
   562 	</xsl:choose>
       
   563 	<xsl:if test="@replace and not($root/descendant::*[(self::component or self::collection or self::package or self::layer) and @id=current()/@replace])">
       
   564 		<!-- only include replace if it's not been used -->
       
   565 		<xsl:copy-of select="@replace"/>
       
   566 	</xsl:if>
       
   567 </xsl:template>
       
   568 
       
   569 <xsl:template match="component" mode="merge-copy-of">
       
   570 	<xsl:param name="remove-before" select="0"/> <!-- set to true if any before attribute is to be removed -->
       
   571 	<xsl:param name="origin"/>	<!--the element containing the @name to use the origin-model attribute  -->
       
   572 	<xsl:param name="root"/> 	<!--the systemModel element in the upstream doc  -->
       
   573 	<xsl:choose>
       
   574 		<!-- this might slow things down, consider making optional -->
       
   575 		<xsl:when test="$root/descendant::collection[@id!=current()/../@id]/component[@id=current()/@id]">
       
   576 			<xsl:message>Warning: <xsl:value-of select="name()"/> "<xsl:value-of select="@id"/>" moved in downstream model. Ignoring moved <xsl:value-of select="name()"/>
       
   577 				<xsl:text>&#xa;</xsl:text>
       
   578 			</xsl:message>
       
   579 		</xsl:when>
       
   580 		<xsl:otherwise>
       
   581 			<xsl:copy>
       
   582 				<xsl:call-template name="merge-copy-of-atts">
       
   583 					<xsl:with-param name="remove-before" select="$remove-before"/>
       
   584 					<xsl:with-param name="root" select="$root"/>
       
   585 				</xsl:call-template>
       
   586 				<xsl:if test="not(@origin-model) and $origin/@name">
       
   587 					<xsl:attribute name="origin-model">
       
   588 						<xsl:value-of select="$origin/@name"/>
       
   589 					</xsl:attribute>
       
   590 					<xsl:if test="not(@root)">
       
   591 						<xsl:copy-of select="$origin/@root"/>
       
   592 					</xsl:if>
       
   593 				</xsl:if>
       
   594 				<xsl:apply-templates select="*|comment()" mode="merge-copy-of">
       
   595 					<xsl:with-param name="origin" select="$origin"/>
       
   596 					<xsl:with-param name="root" select="$root"/>
       
   597 				</xsl:apply-templates>
       
   598 			</xsl:copy>
       
   599 		</xsl:otherwise>
       
   600 	</xsl:choose>
       
   601 </xsl:template>
       
   602 
       
   603 
       
   604 <xsl:template match="unit" mode="merge-copy-of">
       
   605 	<xsl:param name="origin"/>	<!--the element containing the @name to use the origin-model attribute  -->
       
   606 	<xsl:param name="root"/> 	<!--the systemModel element in the upstream doc  -->
       
   607 	<xsl:copy>
       
   608 				<xsl:apply-templates select="@*" mode="merge-copy-of">
       
   609 					<xsl:with-param name="origin" select="$origin"/>
       
   610 					<xsl:with-param name="root" select="$root"/>
       
   611 				</xsl:apply-templates>
       
   612 	</xsl:copy>
       
   613 </xsl:template>
       
   614 
       
   615 
       
   616 
       
   617 
       
   618 <xsl:template match="meta" mode="merge-copy-of">
       
   619 	<xsl:param name="origin"/>	<!--the element containing the @name to use the origin-model attribute  -->
       
   620 	<xsl:param name="root"/> 	<!--the systemModel element in the upstream doc  -->
       
   621 	<xsl:copy>
       
   622 		<xsl:apply-templates select="@*" mode="merge-copy-of">
       
   623 			<xsl:with-param name="origin" select="$origin"/>
       
   624 			<xsl:with-param name="root" select="$root"/>
       
   625 		</xsl:apply-templates>
       
   626 		<xsl:copy-of select="node()"/>
       
   627 	</xsl:copy>
       
   628 </xsl:template>
       
   629 
       
   630 
       
   631 <xsl:template match="unit/@bldFile | unit/@mrp | unit/@base | meta/@href" mode="merge-copy-of">
       
   632 	<xsl:param name="origin" select="/.."/>	<!--the element containing the @name to use the origin-model attribute  -->
       
   633 
       
   634 	<xsl:attribute name="{name()}">
       
   635 		<xsl:choose>
       
   636 			<xsl:when test="not($origin/@pathto)"><xsl:value-of select="."/></xsl:when>
       
   637 			<xsl:when test="(contains(.,'://') and not(contains(substring-before(.,'://'),'/'))) or starts-with(.,'/')"> <!-- absolute URI or absolute path-->
       
   638 				<xsl:value-of select="."/>
       
   639 			</xsl:when>
       
   640 			<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-->
       
   641 				<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>
       
   642 				<xsl:value-of select="."/>
       
   643 			</xsl:when>
       
   644 		<xsl:otherwise> <!-- relative link -->
       
   645 			<xsl:call-template name="joinpath">
       
   646 				<xsl:with-param name="file" select="$origin/@pathto"/>
       
   647 				<xsl:with-param name="rel" select="."/>
       
   648 			</xsl:call-template>
       
   649 		</xsl:otherwise>
       
   650 		</xsl:choose>
       
   651 	</xsl:attribute>
       
   652 </xsl:template>
       
   653 </xsl:stylesheet>