<?xml version="1.0" encoding="UTF-8"?><?xar XSLT?>
<xslt:stylesheet version="1.0" xmlns:xslt="http://www.w3.org/1999/XSL/Transform"
	xmlns:sch="http://www.ascc.net/xml/schematron" >
	<!-- This is a preprocessor for Schematron, which implements abstract
		patterns.  This allows you to say, for example
		
		<pattern name="htmlTable" is-a="table">
			<param formal="row" actual="html:tr"/>
			<param formal="cell" actual="html:td" />
			<param formal="table" actual="html:table" />
		</pattern>
	-->
	
	<!-- Suppress abstract patterns -->
	<xslt:template match="sch:pattern[@abstract='true']" >
		<xslt:comment>Suppressed abstract pattern <xslt:value-of select="@name"/></xslt:comment>
		
	</xslt:template> 
	
	<xslt:template name="macro-expand">
		<xslt:param name="caller"/>
		<xslt:param name="text" />
		<xslt:call-template name="multi-macro-expand">
			<xslt:with-param name="caller" select="$caller"/>
			<xslt:with-param name="text" select="$text"/>
			<xslt:with-param name="paramNumber" select="1"/>
		</xslt:call-template>
		
	</xslt:template>
	
	<xslt:template name="multi-macro-expand">
		<xslt:param name="caller"/>
		<xslt:param name="text" />
		<xslt:param name="paramNumber" />

		
		<xslt:choose>
			<xslt:when test="//sch:pattern[@name=$caller]/sch:param[ $paramNumber]">

				<xslt:call-template name="multi-macro-expand">
					<xslt:with-param name="caller" select="$caller"/>	
					<xslt:with-param name="paramNumber" select="$paramNumber + 1"/>		
					<xslt:with-param name="text" >
						<xslt:call-template name="replace-substring">
							<xslt:with-param name="original" select="$text"/>
							<xslt:with-param name="substring"
							select="concat('$', //sch:pattern[@name=$caller]/sch:param[ $paramNumber ]/@formal)"/>
							<xslt:with-param name="replacement"
								select="//sch:pattern[@name=$caller]/sch:param[ $paramNumber ]/@actual"/>			
						</xslt:call-template>
					</xslt:with-param>						
				</xslt:call-template>
			</xslt:when>
			<xslt:otherwise><xslt:value-of select="$text" /></xslt:otherwise>		
		
		</xslt:choose>
	</xslt:template>
	
	
	<!-- generate the real pattern from an abstract pattern + parameters-->
	<xslt:template name="abstract-to-real" >
		<xslt:param name="caller"/>
		<xslt:param name="is-a" />
		<xslt:for-each select="//sch:pattern[@name= $is-a]">
		<xslt:element name="{name()}">
			<xslt:attribute name="name"><xslt:value-of select="concat( $caller, $is-a)" /></xslt:attribute>
		
			<xslt:for-each select="@*[name()!='abstract'][name()!='is-a'][name()!='name']">
				<xslt:attribute name="{name()}">
					<xslt:value-of select="."/>
				</xslt:attribute>
			</xslt:for-each>
			<xslt:apply-templates select="*|text()" mode="do-pattern">
				<xslt:with-param name="caller"><xslt:value-of select="$caller"/></xslt:with-param>
			</xslt:apply-templates>	
			
		</xslt:element>
		</xslt:for-each>
	</xslt:template>
		
	
	<!-- Suppress uses of abstract patterns -->
	<xslt:template match="sch:pattern[@is-a]">
		<xslt:comment>Start pattern based on abstract <xslt:value-of select="@is-a"/></xslt:comment>
		
		<xslt:call-template name="abstract-to-real" >
			<xslt:with-param name="caller" select="@name" />
			<xslt:with-param name="is-a" select="@is-a" />
		</xslt:call-template>
			
	</xslt:template>
	
	<!-- Generate a non-abstrct pattern -->
	<xslt:template mode="do-pattern" match="*">
		<xslt:param name="caller"/>
		<xslt:element name="{name()}">
			<xslt:for-each select="@*[name()='test' or name()='context' or name()='select']">
				<xslt:attribute name="{name()}">
				<xslt:call-template name="macro-expand">
						<xslt:with-param name="text"><xslt:value-of select="."/></xslt:with-param>
						<xslt:with-param name="caller"><xslt:value-of select="$caller"/></xslt:with-param>
					</xslt:call-template>
				</xslt:attribute>
			</xslt:for-each>	
			<xslt:for-each select="@*[name()!='test'][name()!='context'][name()!='select']">
				<xslt:attribute name="{name()}">
					<xslt:value-of select="."/>
				</xslt:attribute>
			</xslt:for-each>			
			<xslt:apply-templates select="*|text()" mode="do-pattern">
				<xslt:with-param name="caller"><xslt:value-of select="$caller"/></xslt:with-param>
			</xslt:apply-templates>				
		</xslt:element>
	</xslt:template>
	
	<!-- output everything else unchanged -->
	<xslt:template match="*" >
		<xslt:element name="{name()}">
			<xslt:for-each select="@*">
				<xslt:attribute name="{name()}">
					<xslt:value-of select="."/>
				</xslt:attribute>
			</xslt:for-each>
			<xslt:apply-templates select="*|text()"/>
		</xslt:element>
	</xslt:template>
	
	<!-- UTILITIES -->
	<!-- from Doug Tidwell's book XSLT -->
	<xslt:template name="replace-substring">
		<xslt:param name="original" />
		<xslt:param name="substring" />
		<xslt:param name="replacement" select="''"/>
		
		<xslt:variable name="first">
			<xslt:choose>
				<xslt:when test="contains($original, $substring)" >
					<xslt:value-of select="substring-before($original, $substring)"/>
				</xslt:when>
				<xslt:otherwise>
					<xslt:value-of select="$original"/>
				</xslt:otherwise>
			</xslt:choose>
		</xslt:variable>
		
		<xslt:variable name="middle">
			<xslt:choose>
				<xslt:when test="contains($original, $substring)" >
					<xslt:value-of select="$replacement"/>
				</xslt:when>
				<xslt:otherwise>
					<xslt:text></xslt:text>
				</xslt:otherwise>
			</xslt:choose>
		</xslt:variable>
		
		<xslt:variable name="last">
			<xslt:choose>
				<xslt:when test="contains($original, $substring)">
					<xslt:choose>
						<xslt:when test="contains(substring-after($original, $substring),
							$substring)">	
							<xslt:call-template name="replace-substring">
								<xslt:with-param name="original">
									<xslt:value-of select="substring-after($original, $substring)" />
								</xslt:with-param>
								<xslt:with-param name="substring">
									<xslt:value-of select="$substring" />
								</xslt:with-param>
								<xslt:with-param name="replacement">
									<xslt:value-of select="$replacement" />
								</xslt:with-param>
							</xslt:call-template>	
						</xslt:when>	
						<xslt:otherwise>
							<xslt:value-of select="substring-after($original, $substring)"/>
						</xslt:otherwise>
					</xslt:choose>
				</xslt:when>
				<xslt:otherwise>
					<xslt:text></xslt:text>
				</xslt:otherwise>		
			</xslt:choose>				
		</xslt:variable>		
		<xslt:value-of select="concat($first, $middle, $last)"/>
	</xslt:template>	
	
	
</xslt:stylesheet>