<?xml version="1.0"?>
<!-- 
	EXPAND REFERENCES

 	Expand references to complexType, attributeGroup and group.
	This XSLT script is part of a larger package XSD2SCH. 
	Version: 2006-10-12
	Release Type: Beta 
	Developers: Rick Jelliffe, Cheney Xin, Rahul Grewal
	Updates: Please check for updated versions, e.g. at www.schematron.com
	
-->

<!--
	This code copyright 2007 
		Allette Systems Pty. Ltd. (www.allette.com.au), 
		Topologi Pty. Ltd. (www.topologi.com), 
		JSTOR (http://www.jstor.org/)
		and Rick Jelliffe. 
	
	The code was written under sponsorhip of JSTOR The Scholarly Journal Archive
	 
	This code is available under the GPL (v3. http://www.gnu.org/copyleft/gpl.html)
	
 -->


<!-- TODO: This does not handle references to groups in different schemas -->
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
	xmlns:xs="http://www.w3.org/2001/XMLSchema"
	xmlns:fn="http://www.w3.org/TR/xpath-functions">
	
	<xsl:output method="xml" encoding="UTF-8" indent="yes"
		omit-xml-declaration="no"/>
	
	<!-- dereference for element which has type attribute and found type defined before -->
	<xsl:template
		match="xs:element[@name][@type]"
		priority="10" mode="deep">
		<xsl:choose>
			<!-- dereference for element which has type attribute and found type defined in the same schema -->
			<xsl:when test="ancestor::xs:schema/xs:complexType[@name=current()/@type]">
				<xs:element name="{@name}">
					<!-- handle reference to complex type in same schema -->
					<xsl:comment>Expanded from a reference to <xsl:value-of select="@type"/></xsl:comment>
					<xsl:apply-templates
						select="ancestor::xs:schema/xs:complexType[@name=current()/@type]"
						mode="deep"/>
				</xs:element>
			</xsl:when>
			<!-- dereference for element which has type and there is : inside the type means external schema reference -->
			<!-- if it is a embeded xsd type, then don't expand it -->
			<xsl:when test="contains(@type,':') and substring-before(@type,':') != 'xs' and substring-before(@type,':') != 'xsd' and substring-before(@type,':') != 'xsi'">
				<xsl:variable name="prefix" select="substring-before(@type,':')"/>
				<xsl:variable name="typename" select="substring-after(@type,':')"/>
				<xsl:variable name="uri" select="namespace-uri-for-prefix($prefix,.)"/>
				<xsl:comment>Found element who reference external complexType:: prefix=<xsl:value-of select="$prefix"/></xsl:comment>
				<xsl:comment> typename=<xsl:value-of select="$typename"/> uri=<xsl:value-of select="$uri"/></xsl:comment>
				<xsl:choose>
					<!--  if found the complexType with the same name in that schema then replace it -->
					<xsl:when
						test="//xs:schema[@targetNamespace = $uri]/xs:complexType[@name=$typename]">
						<xs:element name="{@name}">
							<xsl:apply-templates
								select="//xs:schema[@targetNamespace = $uri]/xs:complexType[@name=$typename]"
								mode="deep"/>
						</xs:element>
					</xsl:when>
					<!-- otherwise just copy it over without any changes -->
					<xsl:otherwise>
						<xsl:copy>
							<xsl:for-each select="@*|namespace::node()">
								<xsl:copy/>
							</xsl:for-each>
							<xsl:apply-templates mode="deep"/>
						</xsl:copy>
					</xsl:otherwise>
				</xsl:choose>
			</xsl:when>
			<!-- can't find type reference, copy over it as original -->
			<xsl:otherwise>
				<xsl:copy>
					<xsl:for-each select="@*|namespace::node()">
						<xsl:copy/>
					</xsl:for-each>
					<xsl:apply-templates mode="deep"/>
				</xsl:copy>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>
	
	
	<!--	
	<xsl:template match="xs:complexType[@ref]"
	priority="10"  mode="deep">
	<xsl:comment>Expanded from a reference to <xsl:value-of select="@ref"/></xsl:comment>	
	<xsl:apply-templates select="ancestor::xs:schema/xs:complexType[@name=current()/@ref]"  mode="deep"/>	
	</xsl:template>		
	-->
	
	<xsl:template match="xs:group[@ref]" priority="10" mode="deep">
		<xsl:choose>
			<xsl:when test="contains(@ref,':')">
				<xsl:variable name="prefix" select="substring-before(@ref,':')"/>
				<xsl:variable name="typename" select="substring-after(@ref,':')"/>
				<xsl:variable name="uri" select="namespace-uri-for-prefix($prefix,.)"/>
				<xsl:comment>Found group who reference external group prefix= <xsl:value-of select="$prefix"/></xsl:comment>
				<xsl:comment> typename=	<xsl:value-of select="$typename"/> uri=	<xsl:value-of select="$uri"/></xsl:comment>
				<xsl:comment>Expanded from a reference to <xsl:value-of select="@ref"/></xsl:comment>
				<xsl:apply-templates
					select="//xs:schema[@targetNamespace = $uri]/xs:group[@name=@typename]"
					mode="deep"/>
			</xsl:when>
			<xsl:otherwise>
				<xsl:comment>Expanded from a reference to <xsl:value-of select="@ref"/></xsl:comment>
				<xsl:apply-templates
					select="ancestor::xs:schema/xs:group[@name=current()/@ref]"
					mode="deep"/>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>
	
	<xsl:template match="xs:attributeGroup[@ref]" priority="10" mode="deep">
		<xsl:choose>
			<xsl:when test="contains(@ref,':')">
				<xsl:variable name="prefix" select="substring-before(@ref,':')"/>
				<xsl:variable name="typename" select="substring-after(@ref,':')"/>
				<xsl:variable name="uri" select="namespace-uri-for-prefix($prefix,.)"/>
				<xsl:comment>Found attributeGroup who reference external group prefix= <xsl:value-of select="$prefix"/></xsl:comment>
				<xsl:comment> typename=	<xsl:value-of select="$typename"/> uri= <xsl:value-of select="$uri"/></xsl:comment>
				<xsl:comment>Expanded from a reference to <xsl:value-of select="@ref"/></xsl:comment>
				<xsl:apply-templates
					select="//xs:schema[@targetNamespace = $uri]/xs:attributeGroup[@name=@typename]"
					mode="deep"/>
			</xsl:when>
			<xsl:otherwise>
				<xsl:comment>Expanded from a reference to <xsl:value-of select="@ref"/></xsl:comment>
				<xsl:apply-templates
					select="ancestor::xs:schema/xs:attributeGroup[@name=current()/@ref]"
					mode="deep"/>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>
	
	<!-- When expanding, remove the name attribute for validity -->
	<xsl:template match="xs:schema/xs:complexType[@name] | xs:schema/xs:group[@name] | xs:schema/xs:attributeGroup[@name]"
		priority="10" mode="deep">
		<xsl:copy>
			<xsl:for-each select="@*[not(name()='name')] |namespace::node()">
				<xsl:copy/>
			</xsl:for-each>
			<xsl:apply-templates mode="deep"/>
		</xsl:copy>
	</xsl:template>
	
	
	<!-- Strip out global complex type declarations, group declarations, and attribute group declarations-->
	<xsl:template
		match="xs:schema/xs:complexType[@name] | xs:schema/xs:group[@name] | xs:schema/xs:attributeGroup[@name]"
		priority="5">
		<xsl:comment> <xsl:value-of select="@name"/> stripped out</xsl:comment>
	</xsl:template>
	
	<!-- copy everything else -->
	<xsl:template match="schemas | namespace |xs:schema ">
		<xsl:copy>
			<xsl:for-each select="@*|namespace::node()">
				<xsl:copy/>
			</xsl:for-each>
			<xsl:apply-templates/>
		</xsl:copy>
	</xsl:template>
	
	<!-- TODO -->
	<xsl:template match="xs:simpleContent/xs:extension" mode="deep">
		<xsl:variable name="base-decl"
			select="ancestor::xs:schema/xs:complexType[xs:simpleContent][@name=current()/@base] |
					ancestor::xs:schema/xs:simpleType[@name=current()/@base]"/>
		
		<xsl:variable name="simple-base" select="ancestor::xs:schema/xs:simpleType[@name=current()/@base]"/>
		<xsl:variable name="complex-base" select="ancestor::xs:schema/xs:complexType[xs:simpleContent][@name=current()/@base]"/>
		<xsl:choose>
			<xsl:when test="$simple-base">
				<xsl:variable name="rest" select="$simple-base/xs:restriction"/>
				<xs:apply-templates select="$simple-base" mode="deep"/>
			</xsl:when>
			<xsl:when test="$complex-base">
				<xsl:choose>
					<xsl:when test="$complex-base/xs:simpleContent/xs:extension">
						<xsl:apply-templates select="$complex-base" mode="deep"/>
						<xsl:apply-templates select="xs:attribute | xs:attributeGroup" mode="deep"/>
					</xsl:when>
					<xsl:when test="$complex-base/xs:simpleContent/xs:restriction">
						
					</xsl:when>
					
				</xsl:choose>
			</xsl:when>
			
			<!-- can't find base reference, copy over it as original -->
			<xsl:otherwise>
				<xsl:copy>
					<xsl:for-each select="@*|namespace::node()">
						<xsl:copy/>
					</xsl:for-each>
					<xsl:apply-templates mode="deep"/>
				</xsl:copy>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>
	
	
	<!-- TODO: what if the base type also extends from another? need 2 modes - one for elem and one for attrib -->
	<xsl:template match="xs:complexContent/xs:extension" mode="deep">
		<xsl:variable name="base-decl" select="ancestor::xs:schema/xs:complexType[@name=current()/@base]"/>
		<xsl:choose>
			<xsl:when test="$base-decl">
				<xs:sequence>
					<xsl:apply-templates select="$base-decl/*[not(self::xs:attribute or self::xs:attributeGroup)]" mode="deep"/>
					<xsl:apply-templates select="*[not(self::xs:attribute or self::xs:attributeGroup)]" mode="deep"/>
				</xs:sequence>
				<xsl:apply-templates select="$base-decl/(xs:attribute | xs:attributeGroup)" mode="deep"/>
				<xsl:apply-templates select="xs:attribute | xs:attributeGroup" mode="deep"/>
			</xsl:when>
			<!-- can't find base reference, copy over it as original -->
			<xsl:otherwise>
				<xsl:copy>
					<xsl:for-each select="@*|namespace::node()">
						<xsl:copy/>
					</xsl:for-each>
					<xsl:apply-templates mode="deep"/>
				</xsl:copy>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>
	
	<!-- for children of schema (that are not matched above) switch mode and reprocess -->
	<xsl:template match="xs:schema/*" priority="1">
		<xsl:apply-templates mode="deep" select="."/>
	</xsl:template>
	
	<!-- copy everything else -->
	<xsl:template match="*" mode="deep">
		<xsl:copy>
			<xsl:for-each select="@*|namespace::node()">
				<xsl:copy/>
			</xsl:for-each>
			<xsl:apply-templates mode="deep"/>
		</xsl:copy>
	</xsl:template>
	
</xsl:stylesheet>