metatools/sysdeftools/lib/mergesysdef-module.xsl
changeset 663 8e27d440923e
parent 660 66ff3e731c60
--- a/metatools/sysdeftools/lib/mergesysdef-module.xsl	Wed Oct 27 16:03:51 2010 +0800
+++ b/metatools/sysdeftools/lib/mergesysdef-module.xsl	Wed Oct 27 19:16:18 2010 +0800
@@ -136,7 +136,7 @@
 	<xsl:if test="name(*) != name($other/*)">
 		<xsl:message terminate="yes">ERROR: Can only merge system models of the same rank</xsl:message>
 	</xsl:if>
-
+	 
 	<xsl:copy>
 		<xsl:attribute name="schema">
 			<xsl:call-template name="compare-versions">
@@ -213,6 +213,7 @@
 			<xsl:with-param name="replaces" select="$replaces"/>
 		</xsl:apply-templates>
 
+
 		<!-- tack on any remaining layers -->
 		<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)]">
 			<xsl:with-param name="origin" select="$down"/>
@@ -220,45 +221,9 @@
 			<xsl:with-param name="replaces" select="$replaces"/>
 		</xsl:apply-templates>		
 
-		<!-- and now check for error cases, and tack those on -->
-		<xsl:call-template name="check-and-add-out-of-order-items">
-			<xsl:with-param name="match" select="$other/systemModel"/>
-			<xsl:with-param name="down" select="$down"/>
-			<xsl:with-param name="replaces" select="$replaces"/>
-		</xsl:call-template> 
 	</xsl:copy>
 </xsl:template>
 
-<xsl:template name="check-and-add-out-of-order-items"><xsl:param name="match"/><xsl:param name="down"/><xsl:param name="replaces"/>
-	<xsl:if test="$match">
-		<!-- determine the order of the children in the upstream and downstream docs --> 
-		<xsl:variable name="up-order">
-			<xsl:for-each select="*[@id=$match/*[not(@before)]/@id]"><xsl:value-of select="@id"/><xsl:text> </xsl:text></xsl:for-each>
-		</xsl:variable>
-		<xsl:variable name="down-order">
-			<xsl:for-each select="$match/*[@id = current()/*[not(@before)]/@id]"><xsl:value-of select="@id"/> <xsl:text> </xsl:text></xsl:for-each>
-		</xsl:variable>
-
-		<!-- check for error cases, and tack those on -->
-		<xsl:if test="$up-order != $down-order">
-			<xsl:variable name="down-final" select="$match/*[@id = current()/*[not(@before)]/@id][last()]/@id"/>
-				<!-- the last item in the downstream model that is also in the upstream one -->
-
-			<xsl:variable name="out-of-order" select="$match/*[@id][not(@before=current()/*/@id) and not(@id=current()/*/@id) and following-sibling::*[@id=$down-final]]"/>
-				<!-- contains all items in the downstream model that can't be put in order-->
-			<xsl:if test="$out-of-order">
-				<xsl:message>Warning: 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>
-			</xsl:if>
-			<xsl:apply-templates mode="merge-copy-of" select="$out-of-order">
-				<xsl:with-param name="origin" select="$down"/>
-				<xsl:with-param name="root" select="current()/ancestor::SystemDefinition"/>			
-				<xsl:with-param name="replaces" select="$replaces"/>
-			</xsl:apply-templates>			
-		</xsl:if>
-	</xsl:if>
-</xsl:template>
-
-
 <xsl:template match="@*|*|comment()" mode="merge-models"><xsl:copy-of select="."/></xsl:template>
 
 
@@ -308,16 +273,67 @@
 	<xsl:choose>
 		<xsl:when test="not($to-sort)"/>  <!-- nothing left to copy. stop -->
 		<xsl:when test="not($base)"/>  <!-- reached end. stop -->
-		<xsl:otherwise>
-			<xsl:for-each select="$to-sort">
-				<xsl:if test="((@before=$end/@id) or not(@before) or not($base/ancestor::SystemDefinition//*[@id=current()/@before])) and not($base[@id=current()/@id])">
-					<xsl:apply-templates mode="merge-copy-of" select=".">
-						<xsl:with-param name="origin" select="$down"/>
-						<xsl:with-param name="root" select="$end/ancestor::SystemDefinition"/>
-					</xsl:apply-templates>
-				</xsl:if>
-			</xsl:for-each>
-		</xsl:otherwise>	
+		<xsl:when test="$base[1]/@id=$end/following-sibling::*[1]/@id"/> <!-- passed $end. Stop -->
+		<xsl:when test="$base[1]/@id = $to-sort[1]/@id">  <!-- both lists start with same item -->
+			<xsl:if test="$base[1]/@id!=$end/@id"> <!-- not at end, so keep going -->
+				<xsl:call-template name="copy-sorted-content">
+					<xsl:with-param name="base" select="$base[position() != 1]"/>
+					<xsl:with-param name="to-sort" select="$to-sort[position() != 1]"/>
+					<xsl:with-param name="remainder" select="$remainder"/>
+					<xsl:with-param name="start" select="$start"/>
+					<xsl:with-param name="end" select="$end"/>
+					<xsl:with-param name="down" select="$down"/>
+				</xsl:call-template>		
+			</xsl:if>
+		</xsl:when>	
+		<xsl:when test="$remainder[@id = $base[1]/@id]"> <!-- left over item is in $base -->
+			<xsl:call-template name="copy-sorted-content">
+				<xsl:with-param name="base" select="$base[position() != 1]"/>
+				<xsl:with-param name="to-sort" select="$to-sort"/>
+				<xsl:with-param name="remainder" select="$remainder[@id != $base[1]/@id]"/>
+				<xsl:with-param name="start" select="$start"/>
+				<xsl:with-param name="end" select="$end"/>
+				<xsl:with-param name="down" select="$down"/>
+			</xsl:call-template>		
+		</xsl:when>
+		<xsl:when test="not($base[@id = $to-sort[1]/@id])"> <!-- in to-sort, but not base -->		
+			<xsl:if test="$base[1]/@id=$end/@id  and not($base[@id=$to-sort[1]/@before])">
+			 	<!-- if at end, then this needs to be copied
+					don't copy if the before ID is found in $base	-->
+				<xsl:apply-templates mode="merge-copy-of" select="$to-sort[1]">
+					<xsl:with-param name="origin" select="$down"/>
+					<xsl:with-param name="root" select="$end/ancestor::SystemDefinition"/>
+				</xsl:apply-templates>
+			</xsl:if>			
+		<xsl:call-template name="copy-sorted-content">
+			<xsl:with-param name="base" select="$base"/>
+			<xsl:with-param name="to-sort" select="$to-sort[position() != 1]"/>
+			<xsl:with-param name="remainder" select="$remainder"/>
+			<xsl:with-param name="start" select="$start"/>
+			<xsl:with-param name="end" select="$end"/>
+			<xsl:with-param name="down" select="$down"/>
+		</xsl:call-template>		
+		</xsl:when>	
+		<xsl:when test="not($to-sort[@id = $base[1]/@id])"> <!-- in base, but not to-sort -->		
+		<xsl:call-template name="copy-sorted-content">
+			<xsl:with-param name="base" select="$base[position() != 1]"/>
+			<xsl:with-param name="to-sort" select="$to-sort"/>
+			<xsl:with-param name="remainder" select="$remainder"/>
+			<xsl:with-param name="start" select="$start"/>
+			<xsl:with-param name="end" select="$end"/>
+			<xsl:with-param name="down" select="$down"/>
+		</xsl:call-template>		
+		</xsl:when>	
+		<xsl:when test="$base[@id = $to-sort[1]/@id]"> <!-- is in base, but not 1st one-->
+			<xsl:call-template name="copy-sorted-content">
+				<xsl:with-param name="base" select="$base"/>
+				<xsl:with-param name="to-sort" select="$to-sort[position() != 1] "/>
+				<xsl:with-param name="remainder" select="$remainder | $to-sort[1]"/>
+				<xsl:with-param name="start" select="$start"/>
+				<xsl:with-param name="end" select="$end"/>
+				<xsl:with-param name="down" select="$down"/>
+			</xsl:call-template>
+		</xsl:when>	
 	</xsl:choose>
 </xsl:template>
 
@@ -358,22 +374,6 @@
 </xsl:template>
 
 
-<xsl:template name="best-prev"><xsl:param name="cur" select="."/><xsl:param name="alt"/>
-<xsl:if test="$alt">
-<xsl:variable name="prev" select="$cur/preceding-sibling::*[@id][1]"/> 
-<xsl:choose>
-	<xsl:when test="not($prev)"/>
-	<xsl:when test="$alt/preceding-sibling::*[@id=$prev/@id]"><xsl:value-of select="$prev/@id"/></xsl:when>
-	<xsl:otherwise>
-		<xsl:call-template name="best-prev">
-			<xsl:with-param name="cur" select="$prev"/>
-			<xsl:with-param name="alt" select="$alt"/>
-		</xsl:call-template>
-	</xsl:otherwise>
-</xsl:choose>
-</xsl:if>
-</xsl:template>
-
 <xsl:template match="layer | package | collection | component" mode="merge-models">
 	<xsl:param name="other"/>	<!-- the downstream item of the parent's rank that contains a potential items this is merged with -->
 	<xsl:param name="up"/>
@@ -386,9 +386,9 @@
 	<xsl:choose>
 		<xsl:when test="$replaces[.=$this/@id] or (self::component and $match)">  <!-- replace the item instead of merge -->
 			<xsl:message>Note: <xsl:value-of select="name()"/> "<xsl:value-of select="@id"/>" in "<xsl:value-of select="../@id"/>" <xsl:choose>
-					<xsl:when test="self::component and $match">overridden in downstream sysdef</xsl:when>
-					<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>
-				</xsl:choose>
+				<xsl:when test="self::component and $match">overridden in downstream sysdef</xsl:when>
+				<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>
+			</xsl:choose>
 			</xsl:message>
 			<!-- if the removed item is in the downstream doc, just copy that and ignore the upstream contents -->
 			<xsl:apply-templates mode="merge-copy-of" select="$match">
@@ -400,77 +400,49 @@
 		<xsl:otherwise>
 			<!-- remove this if it's in the list of stuff to be replaced-->
 
-<xsl:variable name="prev-id">
-	<xsl:call-template name="best-prev">
-		<xsl:with-param name="alt" select="$match"/>
-	</xsl:call-template>
-</xsl:variable>
-
+	<!-- prev = the previous item before the current one (no metas, only named items)-->
+	<xsl:variable name="prev" select="preceding-sibling::*[@id][1]"/> 
 
-	<!-- check the order of the items in the upstream and downstream doc. If they don't match up, we can't merge them nicely -->
-	<xsl:variable name="up-order">
-		<xsl:for-each select="../*[@id=$match/../*[not(@before)]/@id]"><xsl:value-of select="@id"/><xsl:text> </xsl:text></xsl:for-each>
-	</xsl:variable>
-	<xsl:variable name="down-order">
-		<xsl:for-each select="$match/../*[@id = current()/../*[not(@before)]/@id]"><xsl:value-of select="@id"/> <xsl:text> </xsl:text></xsl:for-each>
-	</xsl:variable>
-
-	<!-- prev = the previous item before the current one (no metas, only named items)-->
-	<xsl:variable name="prev" select="preceding-sibling::*[@id=$prev-id]"/> 
-
-
-	<!-- copy all items between this and prev that are solely in the downstream model -->	 		
-
-	<!-- <xsl:variable name="upstream-ids" select="ancestor::SystemDefinition//@id[parent::component or parent::collection or parent::package or parent::layer]"/> -->
-	<xsl:variable name="upstream-ids" select="../*/@id"/> <!-- this is much faster than using all IDs. before only currently works in the same parent anyway -->
-
-	<!-- $upstream-ids is used to avoid inserting an item that's being moved -->
+	<!-- copy all items between this and prev  that are solely in the downstream model -->	 		
 
 	<xsl:choose>
-		<xsl:when test="$match and $up-order != $down-order">
-		<!-- 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 -->
-				<xsl:message>Warning: Order of <xsl:value-of select="name()"/>s in upstream <xsl:value-of select="../@id"/>
-				<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>
-		</xsl:when>
-
-		<xsl:when test="$match and $prev">
+		<xsl:when test="$match and (not($prev) or $other/*[@id= $prev/@id] )">
 			<xsl:call-template name="copy-sorted-content">
 				<xsl:with-param name="base" select="../*[@id]"/>
-				<xsl:with-param name="to-sort" select="$other/*[@id and not(@before=$upstream-ids)][following-sibling::*[@id=$match/@id]][preceding-sibling::*[@id=$prev/@id]]"/>
+				<xsl:with-param name="to-sort" select="$other/*[@id]"/>
 				<xsl:with-param name="start" select="$prev"/>
 				<xsl:with-param name="end" select="."/>
 				<xsl:with-param name="down" select="$down"/>
 			</xsl:call-template>
 		</xsl:when>
-		<xsl:when test="$match and not($prev)">
-			<xsl:call-template name="copy-sorted-content">
-				<xsl:with-param name="base" select="../*[@id]"/>
-				<xsl:with-param name="to-sort" select="$other/*[@id and not(@before=$upstream-ids)][following-sibling::*[@id=$match/@id]]"/>
-				<xsl:with-param name="start" select="$prev"/>
-				<xsl:with-param name="end" select="."/>
-				<xsl:with-param name="down" select="$down"/>
-			</xsl:call-template>
-		</xsl:when>
+	<xsl:when test="not($match/preceding-sibling::*[@id=$this/../*/@id]) and $other/*[@id= current()/@id]/preceding-sibling::*[@id and not(@before)]">
+		<!-- if this is the first item in other that's also in this, then put all new items from other here -->
+		<xsl:apply-templates mode="merge-copy-of" select="$match/preceding-sibling::*[@id and not(@before)]">
+			<xsl:with-param name="origin" select="$down"/>
+			<xsl:with-param name="root" select="$this/ancestor::SystemDefinition"/>	
+			<xsl:with-param name="replaces" select="$replaces"/>
+		</xsl:apply-templates>
+	</xsl:when>
 	</xsl:choose>
 
  	<!-- just copy anything identified as being before this, assume they're all ok -->
-
 	<xsl:apply-templates mode="merge-copy-of" select="$other/*[@before=current()/@id]">
 		<xsl:with-param name="remove-before" select="1"/>
 		<xsl:with-param name="origin" select="$down"/>
 		<xsl:with-param name="root" select="$this/ancestor::SystemDefinition"/>	
 		<xsl:with-param name="replaces" select="$replaces"/>
 	</xsl:apply-templates>
+
 	
 	<xsl:copy>
 		<xsl:apply-templates select="@*" mode="merge-models"> <!-- copy upstream attributes -->
 			<xsl:with-param name="other" select="$match"/>
 		</xsl:apply-templates>
-		<xsl:if test="self::component and not(@origin-model) and ($up/@name or ancestor::systemModel/@name)">
+		
+		<xsl:if test="self::component and not(@origin-model) and $up/@name">
 			<!-- insert origin-model and optional root for components only -->
 			<xsl:attribute name="origin-model">
 				<xsl:value-of select="$up/@name"/>
-				<xsl:if test="not($up/@name)"><xsl:value-of select="ancestor::systemModel/@name"/></xsl:if>
 			</xsl:attribute>
 			<xsl:if test="not(@root)">
 				<xsl:copy-of select="$up/@root"/>
@@ -523,16 +495,9 @@
 				</xsl:for-each>
 			</xsl:otherwise>
 		</xsl:choose>
+	</xsl:copy>
 
-		<!-- and now check for error cases, and tack those on -->
-		<xsl:call-template name="check-and-add-out-of-order-items">
-			<xsl:with-param name="match" select="$match"/>
-			<xsl:with-param name="down" select="$down"/>
-			<xsl:with-param name="replaces" select="$replaces"/>
-		</xsl:call-template> 
-
-	</xsl:copy>
- 	</xsl:otherwise>
+		</xsl:otherwise>
 	</xsl:choose>
 </xsl:template>
 
@@ -618,10 +583,9 @@
 					<xsl:with-param name="remove-before" select="$remove-before"/>
 					<xsl:with-param name="root" select="$root"/>
 				</xsl:call-template>
-				<xsl:if test="not(@origin-model) and ($origin/@name or ancestor::systemModel/@name)">
+				<xsl:if test="not(@origin-model) and $origin/@name">
 					<xsl:attribute name="origin-model">
 						<xsl:value-of select="$origin/@name"/>
-						<xsl:if test="not($origin/@name)"><xsl:value-of select="ancestor::systemModel/@name"/></xsl:if>
 					</xsl:attribute>
 					<xsl:if test="not(@root)">
 						<xsl:copy-of select="$origin/@root"/>