<?xml version="1.0" encoding="UTF-8" ?>
<schema xmlns="http://purl.oclc.org/dsdl/schematron" queryBinding="xslt2" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:sqf="http://www.schematron-quickfix.com/validator/process" xmlns:akn="http://docs.oasis-open.org/legaldocml/ns/akn/3.0" xmlns:local="local">
	<ns prefix="akn" uri="http://docs.oasis-open.org/legaldocml/ns/akn/3.0" />
	<ns prefix="local" uri="local" />

	<!-- keys -->
	
	<xsl:key name="eId" match="*[exists(@eId)]" use="@eId" />
	
	
	<!-- global variables -->
	
	<let name="primary-types" value="('asp', 'sppubb', 'spprib', 'sphybb')" />
	<let name="secondary-types" value="('uksi', 'ssi', 'nisr', 'nisi', 'nisro')" />
	<let name="draft-secondary-types" value="('ukdsi', 'sdsi', 'nidsr')" />
	<let name="all-secondary-types" value="($secondary-types, $draft-secondary-types)" />
	<let name="all-subtypes" value="('Government Bill', 'Member’s Bill', 'Committee Bill', 'Consolidation Bill', 'Regulations', 'Order', 'Order in Council', 'Rules', 'Scheme', 'Approval Instrument', 'Direction', 'Warrant', 'Resolution', 'Other')" />

	<let name="doc-type" value="/akn:akomaNtoso/*/@name" />
	<let name="frbr-subtype" value="/akn:akomaNtoso/akn:*/akn:meta/akn:identification/akn:FRBRWork/akn:FRBRsubtype/@value" />
	<let name="doc-subtype" value="if (starts-with($frbr-subtype,'#')) then key('eId',substring($frbr-subtype,2))/@showAs else $frbr-subtype" />
	<let name="is-primary" value="$doc-type = $primary-types" />
	<let name="is-scottish-act" value="$doc-type = ('asp', 'sppubb', 'spprib', 'sphybb')" />
	
	
	<!-- functions -->

	<xsl:function name="local:resolve-helper" as="xs:string">
		<xsl:param name="show-as" as="attribute(showAs)" />
		<xsl:variable name="unresolved-parts" as="xs:string*" select="tokenize($show-as,' ')" />
		<xsl:variable name="resolved-parts" as="xs:string*">
			<xsl:for-each select="$unresolved-parts">
				<xsl:choose>
					<xsl:when test="starts-with(.,'#var')">
						<xsl:variable name="id" as="xs:string" select="substring(., 2)" />
						<xsl:variable name="var" as="element()" select="key('eId', $id, root($show-as))" />
						<xsl:sequence select="local:resolve-helper($var/@showAs)" />
					</xsl:when>
					<xsl:otherwise>
						<xsl:sequence select="." />
					</xsl:otherwise>
				</xsl:choose>
			</xsl:for-each>
		</xsl:variable>
		<xsl:sequence select="string-join($resolved-parts, ' ')" />
	</xsl:function>
		
	<xsl:function name="local:resolve" as="xs:string">
		<xsl:param name="n" as="node()" />
		<xsl:choose>
			<xsl:when test="$n/self::akn:ref[starts-with(@href,'#var')]">
				<xsl:variable name="id" as="xs:string" select="substring($n/@href, 2)" />
				<xsl:variable name="show-as" as="attribute(showAs)" select="key('eId', $id, root($n))/@showAs" />
				<xsl:sequence select="local:resolve-helper($show-as)" />
			</xsl:when>
			<xsl:when test="$n/self::*">
				<xsl:variable name="children" as="xs:string*" select="$n/child::node()/local:resolve(.)" />
				<xsl:sequence select="string-join($children, '')" />
			</xsl:when>
			<xsl:otherwise>
				<xsl:sequence select="string($n)" />
			</xsl:otherwise>
		</xsl:choose>
	</xsl:function>

	<xsl:function name="local:is-within-quoted-structure" as="xs:boolean">
		<xsl:param name="n" as="node()" />
		<xsl:sequence select="exists($n/ancestor::akn:quotedStructure) or exists($n/ancestor::akn:embeddedStructure)" />
	</xsl:function>

	<xsl:function name="local:is-within-schedule" as="xs:boolean">
		<xsl:param name="n" as="node()" />
		<xsl:sequence select="exists($n/ancestor::akn:hcontainer[@name='schedule'][not(local:is-within-quoted-structure(.))])" />
	</xsl:function>

	<xsl:function name="local:is-level" as="xs:boolean">
		<xsl:param name="e" as="element()" />
		<xsl:choose>
			<xsl:when test="$e/self::akn:hcontainer[@name='groupOfParts']">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:when test="$e/self::akn:part">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:when test="$e/self::akn:chapter">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:when test="$e/self::akn:hcontainer[@name='crossheading']">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:when test="$e/self::akn:hcontainer[@name='subheading']">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:when test="$e/self::akn:section">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:when test="$e/self::akn:hcontainer[@name='regulation']">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:when test="$e/self::akn:rule">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:when test="$e/self::akn:article">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:when test="$e/self::akn:subsection">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:when test="$e/self::akn:paragraph">
				<xsl:sequence select="true()" />
			</xsl:when>
			<!-- more -->
			<xsl:when test="$e/self::akn:hcontainer[@name='scheduleParagraph']">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:when test="$e/self::akn:hcontainer[@name='scheduleSubparagraph']">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:when test="$e/self::akn:hcontainer[@name='SIParagraph']">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:otherwise>
				<xsl:sequence select="false()" />
			</xsl:otherwise>
		</xsl:choose>
	</xsl:function>

	<xsl:function name="local:get-level-name" as="xs:string">
		<xsl:param name="level" as="element()" />
		<xsl:sequence select="if ($level/self::akn:hcontainer) then $level/@name/string() else local-name($level)" />
	</xsl:function>

	<xsl:function name="local:get-child-levels" as="element()*">
		<xsl:param name="level" as="element()" />
		<xsl:sequence select="$level/*[not(self::akn:num) and not(self::akn:heading) and not(self::akn:subheading) and not(self::akn:intro) and not(self::akn:content) and not(self::akn:wrapUp)]" />
	</xsl:function>

	<xsl:function name="local:get-invalid-child-levels" as="element()*">
		<xsl:param name="parent" as="element()" />
		<xsl:variable name="children" as="element()*" select="local:get-child-levels($parent)" />
		<xsl:sequence select="$children[not(local:levels-are-valid($parent, .))]" />
	</xsl:function>
	
	<xsl:function name="local:is-si-section" as="xs:boolean">
		<xsl:param name="level" as="element()" />
		<xsl:sequence select="($doc-type = $all-secondary-types) and exists($level/self::akn:section[not(local:is-within-quoted-structure(.))])" />
	</xsl:function>

	<xsl:function name="local:is-si-subsection" as="xs:boolean">
		<xsl:param name="level" as="element()" />
		<xsl:sequence select="($doc-type = $all-secondary-types) and exists($level/self::akn:subsection[not(local:is-within-quoted-structure(.))])" />
	</xsl:function>

	<xsl:function name="local:is-p1" as="xs:boolean">
		<xsl:param name="level" as="element()" />
		<xsl:choose>
			<xsl:when test="$level/@class = ('prov1','schProv1')">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:when test="local:is-within-schedule($level)">
				<xsl:sequence select="exists($level/self::akn:hcontainer[@name='scheduleParagraph'])" />
			</xsl:when>
			<xsl:when test="$is-primary">
				<xsl:sequence select="exists($level/self::akn:section[not(local:is-within-quoted-structure(.))])" />
			</xsl:when>
			<xsl:when test="$doc-subtype = 'Regulations'">
				<xsl:sequence select="exists($level/self::akn:hcontainer[@name='regulation'])" />
			</xsl:when>
			<xsl:when test="$doc-subtype = 'Rules'">
				<xsl:sequence select="exists($level/self::akn:rule)" />
			</xsl:when>
			<xsl:when test="$level/self::akn:article">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:otherwise>
				<xsl:sequence select="false()" />
			</xsl:otherwise>
		</xsl:choose>
	</xsl:function>

	<xsl:function name="local:is-p2" as="xs:boolean">
		<xsl:param name="level" as="element()" />
		<xsl:choose>
			<xsl:when test="$level/@class = ('prov2','schProv2')">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:when test="local:is-within-schedule($level)">
				<xsl:sequence select="exists($level/self::akn:hcontainer[@name='scheduleSubparagraph'])" />
			</xsl:when>
			<xsl:when test="$is-primary">
				<xsl:sequence select="exists($level/self::akn:subsection)" />
			</xsl:when>
			<xsl:otherwise>
				<xsl:sequence select="exists($level/self::akn:hcontainer[@name='SIParagraph'])" />
			</xsl:otherwise>
		</xsl:choose>
	</xsl:function>

	<xsl:function name="local:levels-are-valid" as="xs:boolean">
		<xsl:param name="parent" as="element()" />
		<xsl:param name="child" as="element()" />
		<xsl:choose>
			<xsl:when test="$parent/self::akn:body">
				<xsl:sequence select="exists($child/self::akn:hcontainer[@name='groupOfParts']) or exists($child/self::akn:part) or exists($child/self::akn:chapter) or exists($child/self::akn:hcontainer[@name='crossheading']) or exists($child/self::akn:*[local:is-p1(.)])" />
			</xsl:when>
			<xsl:when test="local:is-within-quoted-structure($parent)">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:when test="$parent/self::akn:hcontainer[@name='groupOfParts']">
				<xsl:sequence select="exists($child/self::akn:part)" />
			</xsl:when>
			<xsl:when test="$parent/self::akn:part">
				<xsl:sequence select="exists($child/self::akn:chapter) or exists($child/self::akn:hcontainer[@name='crossheading']) or exists($child/self::akn:*[local:is-p1(.)])" />
			</xsl:when>
			<xsl:when test="$parent/self::akn:chapter">
				<xsl:sequence select="exists($child/self::*[local:is-si-section(.)]) or exists($child/self::akn:hcontainer[@name='crossheading']) or exists($child/self::akn:*[local:is-p1(.)])" />
			</xsl:when>
			<xsl:when test="$parent/self::akn:*[local:is-si-section(.)]">
				<xsl:sequence select="exists($child/self::akn:*[local:is-si-subsection(.)]) or exists($child/self::akn:hcontainer[@name='crossheading']) or exists($child/self::akn:*[local:is-p1(.)])" />
			</xsl:when>
			<xsl:when test="$parent/self::akn:hcontainer[@name='crossheading']">
				<xsl:sequence select="exists($child/self::akn:hcontainer[@name='subheading']) or exists($child/self::akn:*[local:is-p1(.)])" />
			</xsl:when>
			<xsl:when test="$parent/self::akn:hcontainer[@name='subheading']">
				<xsl:sequence select="exists($child/self::akn:hcontainer[@name='subheading']) or exists($child/self::akn:*[local:is-p1(.)])" />
			</xsl:when>
			<xsl:when test="$parent/self::akn:*[local:is-p1(.)]">
				<xsl:sequence select="exists($child/self::akn:*[local:is-p2(.)]) or exists($child/self::akn:paragraph) or exists($child/self::akn:hcontainer[@name=('definition','step','unnumberedItem')])" />
			</xsl:when>
			<xsl:when test="$parent/self::akn:*[local:is-p2(.)]">
				<xsl:sequence select="exists($child/self::akn:paragraph) or exists($child/self::akn:hcontainer[@name=('definition','step','unnumberedItem')])" />
			</xsl:when>
			<xsl:when test="$parent/self::akn:paragraph">
				<xsl:sequence select="exists($child/self::akn:subparagraph) or exists($child/self::akn:hcontainer[@name=('definition','step','unnumberedItem')])" />
			</xsl:when>
			<xsl:when test="$parent/self::akn:hcontainer[@name='definition']">
				<xsl:sequence select="exists($child/self::akn:subparagraph)" />
			</xsl:when>
			<xsl:when test="$parent/self::akn:hcontainer[@name=('definition','step','unnumberedItem')]">
				<xsl:sequence select="exists($child/self::akn:paragraph)" />
			</xsl:when>
			<xsl:otherwise>
				<xsl:sequence select="true()" />
			</xsl:otherwise>
		</xsl:choose>
	</xsl:function>
	
	<xsl:function name="local:level-must-have-number" as="xs:boolean">
		<xsl:param name="level" as="element()" />
		<xsl:choose>
			<xsl:when test="$level/self::akn:hcontainer[@name='groupOfParts']">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:when test="$level/self::akn:part">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:when test="$level/self::akn:chapter">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:when test="$level/self::akn:*[local:is-si-section(.)]">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:when test="$level/self::akn:*[local:is-si-subsection(.)]">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:when test="$level/self::akn:*[local:is-p1(.)]">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:when test="$level/self::akn:*[local:is-p2(.)]">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:when test="$level/self::akn:paragraph">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:otherwise>
				<xsl:sequence select="false()" />
			</xsl:otherwise>
		</xsl:choose>
	</xsl:function>

	<xsl:function name="local:level-may-have-number" as="xs:boolean">
		<xsl:param name="level" as="element()" />
		<xsl:choose>
			<xsl:when test="$level/self::akn:hcontainer[@name='crossheading']">
				<xsl:sequence select="false()" />
			</xsl:when>
			<xsl:when test="$level/self::akn:hcontainer[@name='subheading']">
				<xsl:sequence select="false()" />
			</xsl:when>
			<xsl:otherwise>
				<xsl:sequence select="true()" />
			</xsl:otherwise>
		</xsl:choose>
	</xsl:function>

	<xsl:function name="local:level-must-have-heading" as="xs:boolean">
		<xsl:param name="level" as="element()" />
		<xsl:choose>
			<xsl:when test="$level/self::akn:hcontainer[@name='groupOfParts']">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:when test="$level/self::akn:part">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:when test="$level/self::akn:chapter">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:when test="$level/self::akn:*[local:is-si-section(.)]">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:when test="$level/self::akn:*[local:is-si-subsection(.)]">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:when test="$level/self::akn:hcontainer[@name='crossheading']">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:when test="$level/self::akn:hcontainer[@name='subheading']">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:otherwise>
				<xsl:sequence select="false()" />
			</xsl:otherwise>
		</xsl:choose>
	</xsl:function>
	<xsl:function name="local:level-may-have-heading" as="xs:boolean">
		<xsl:param name="level" as="element()" />
		<xsl:choose>
			<xsl:when test="$level/self::*[local:is-p2(.)]">
				<xsl:sequence select="false()" />
			</xsl:when>
			<xsl:when test="$level/self::akn:paragraph">
				<xsl:sequence select="false()" />
			</xsl:when>
			<xsl:otherwise>
				<xsl:sequence select="true()" />
			</xsl:otherwise>
		</xsl:choose>
	</xsl:function>
	
	<xsl:function name="local:level-may-have-content" as="xs:boolean">
		<xsl:param name="level" as="element()" />
		<xsl:choose>
			<xsl:when test="$level/self::akn:hcontainer[@name='groupOfParts']">
				<xsl:sequence select="false()" />
			</xsl:when>
			<xsl:when test="$level/self::akn:part">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:when test="$level/self::akn:chapter">
				<xsl:sequence select="false()" />
			</xsl:when>
			<xsl:when test="$level/self::akn:*[local:is-si-section(.)]">
				<xsl:sequence select="false()" />
			</xsl:when>
			<xsl:when test="$level/self::akn:*[local:is-si-subsection(.)]">
				<xsl:sequence select="false()" />
			</xsl:when>
			<xsl:otherwise>
				<xsl:sequence select="true()" />
			</xsl:otherwise>
		</xsl:choose>
	</xsl:function>

	<xsl:function name="local:level-must-have-opening-words" as="xs:boolean">
		<xsl:param name="level" as="element()" />
		<xsl:choose>
			<xsl:when test="$level/self::akn:paragraph">
				<xsl:sequence select="false()" />
			</xsl:when>
			<xsl:otherwise>
				<xsl:sequence select="false()" />
			</xsl:otherwise>
		</xsl:choose>
	</xsl:function>
	<xsl:function name="local:level-may-have-opening-words" as="xs:boolean">
		<xsl:param name="level" as="element()" />
		<xsl:choose>
			<xsl:when test="not(local:level-may-have-content($level))">
				<xsl:sequence select="false()" />
			</xsl:when>
			<xsl:otherwise>
				<xsl:sequence select="true()" />
			</xsl:otherwise>
		</xsl:choose>
	</xsl:function>
	
	<xsl:function name="local:normalize-term-for-alphabeticalization" as="xs:string">
		<xsl:param name="item" as="item()?" />
		<xsl:variable name="term" as="xs:string" select="lower-case(normalize-space($item))" />
		<xsl:choose>
			<xsl:when test="starts-with($term, 'a ')">
				<xsl:sequence select="substring($term, 3)" />
			</xsl:when>
			<xsl:when test="starts-with($term, 'an ')">
				<xsl:sequence select="substring($term, 4)" />
			</xsl:when>
			<xsl:when test="starts-with($term, 'the ')">
				<xsl:sequence select="substring($term, 5)" />
			</xsl:when>
			<xsl:otherwise>
				<xsl:sequence select="$term" />
			</xsl:otherwise>
		</xsl:choose>
	</xsl:function>
	
	<xsl:function name="local:are-in-alphabetical-order" as="xs:boolean">
		<xsl:param name="one" as="item()?" />
		<xsl:param name="two" as="item()?" />
		<xsl:variable name="one" as="xs:string" select="local:normalize-term-for-alphabeticalization($one)" />
		<xsl:variable name="two" as="xs:string" select="local:normalize-term-for-alphabeticalization($two)" />
		<xsl:choose>
			<xsl:when test="($one = '') or ($two = '')">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:when test="matches($one, '$\d') and not(matches($two, '$\d'))">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:when test="matches($two, '$\d') and not(matches($one, '$\d'))">
				<xsl:sequence select="true()" />
			</xsl:when>
			<xsl:otherwise>
				<xsl:sequence select="$one le $two" />
			</xsl:otherwise>
		</xsl:choose>
	</xsl:function>
	
	<xsl:function name="local:last-date" as="xs:date?">
		<xsl:param name="dates" as="element(akn:date)*" />
		<xsl:variable name="sorted" as="xs:date*">
			<xsl:for-each select="$dates">
				<xsl:sort select="@date" order="descending" />
				<xsl:sequence select="xs:date(substring(@date, 1, 10))" />
			</xsl:for-each>
		</xsl:variable>
		<xsl:sequence select="$sorted[1]" />
	</xsl:function>


	<!-- phases -->
	
	<phase id="drafting">
		<active pattern="body" />
		<active pattern="hcontainer" />
		<active pattern="schedules" />
		<active pattern="schedule" />
		<active pattern="number" />
		<active pattern="heading" />
		<active pattern="content" />
		<active pattern="si-banner" />
		<active pattern="si-title" />
	</phase>
	<phase id="preflight-mandatory">
		<active pattern="metadata" />
		<active pattern="two-or-more" />
		<active pattern="all-internal-refs-exist" />
		<active pattern="si-number" />
		<active pattern="si-year" />
		<active pattern="made-date-signature-date" />
		<active pattern="si-preflight-signature" />
		<active pattern="preflight-mandatory-misc" />
	</phase>
	<phase id="preflight-advisory">
		<active pattern="draft-si-not-laid" />
		<active pattern="si-subjects" />
		<active pattern="defs-alphabetical-order" />
		<active pattern="preflight-advisory-misc" />
	</phase>
	
	
	<!-- drafting patterns -->

	<pattern id="metadata">
		<rule context="akn:FRBRsubtype">
			<let name="value" value="if (starts-with(@value, '#var')) then key('eId', substring(@value,2))/@showAs else @value" />
			<assert test="$value = $all-subtypes">#preflight-mandatory:The subtype "<value-of select="$value" />" is invalid</assert>
		</rule>
	</pattern>

	<pattern id="body">
		<rule context="akn:body">
			<let name="children" value="*[not(self::akn:hcontainer[@name='signatures'])][not(self::akn:hcontainer[@name='schedules'])]" />
			<assert test="count(distinct-values($children/local:get-level-name(.))) le 1">#drafting:The body should be evenly divided</assert>
			<let name="invalid-children" value="$children[not(local:levels-are-valid(current(), .))]" />
			<assert test="empty($invalid-children)">#drafting:The body should not contain a <value-of select="local:get-level-name($invalid-children[1])" /></assert>
		</rule>
	</pattern>
	
	<pattern id="hcontainer">
		<rule context="akn:*[local:is-level(.)]">
			
			<assert test="not(local:level-must-have-number(.) and empty(akn:num))">#drafting:A <value-of select="local:get-level-name(.)" /> should start with a number</assert>
			<assert test="local:level-may-have-number(.) or empty(akn:num)">#drafting:A <value-of select="local:get-level-name(.)" /> should not have a number</assert>
			
			<assert test="not(local:level-must-have-heading(.) and empty(akn:heading))">#drafting:A <value-of select="local:get-level-name(.)" /> should have a heading</assert>
			<assert test="local:level-may-have-heading(.) or empty(akn:heading)">#drafting:A <value-of select="local:get-level-name(.)" /> should not have a heading</assert>
			
			<let name="children" value="local:get-child-levels(.)" />
			
			<assert test="local:level-may-have-content(.) or empty(akn:content | akn:intro | akn:wrapUp)">#drafting:A <value-of select="local:get-level-name(.)" /> should not have content</assert>
			<assert test="not(local:level-may-have-content(.) and empty($children) and empty(akn:content))">#drafting:A <value-of select="local:get-level-name(.)" /> should have content if not subdivided</assert>
			
			<assert test="not(local:level-must-have-opening-words(.) and empty(akn:intro))">#drafting:A <value-of select="local:get-level-name(.)" /> must have opening words</assert>
			<assert test="local:level-may-have-opening-words(.) or empty(akn:intro)">#drafting:There should not be opening words in a <value-of select="local:get-level-name(.)" /></assert>
			<assert test="exists(akn:intro) or empty(akn:wrapUp)">#drafting:There should be opening words to correspond to the closing words</assert>
			
			<assert test="count(distinct-values($children/local:get-level-name(.))) le 1">#drafting:A <value-of select="local:get-level-name(.)" /> should be evenly divided</assert>
			
			<let name="invalid-children" value="$children[not(local:levels-are-valid(current(), .))]" />
			<assert test="empty($invalid-children)">#drafting:A <value-of select="local:get-level-name(.)" /> should not contain a <value-of select="local:get-level-name($invalid-children[1])" /></assert>
		</rule>
	</pattern>
	
	<pattern id="schedules">
		<rule context="akn:hcontainer[@name='schedules']">
			<assert test="exists(akn:hcontainer[@name='schedule'])">#drafting:There are no schedules in the schedules container so it is unnecessary</assert>
			<assert test="empty(akn:num)">#drafting:There should be no &lt;num&gt; element for the schedules container</assert>
			<assert test="$is-scottish-act or count(akn:hcontainer[@name='schedule']) le 1 or exists(akn:heading)" sqf:fix="add-schedules-heading">#drafting:There should be a heading "Schedules" as there is more than one schedule</assert>
			<sqf:fix id="add-schedules-heading">
				<sqf:description>
					<sqf:title>Add a Schedules heading</sqf:title>
				</sqf:description>
				<sqf:add>
					<akn:heading>Schedules</akn:heading>
				</sqf:add>
			</sqf:fix>
			<assert test="not((count(akn:hcontainer[@name='schedule']) gt 1) and exists(akn:heading) and not(akn:heading = ('Schedules','SCHEDULES')))" sqf:fix="replace-schedules-heading">#drafting:The Schedules heading should be "Schedules"</assert>
			<sqf:fix id="replace-schedules-heading">
				<sqf:description>
					<sqf:title>Change the Schedules heading to "Schedules"</sqf:title>
				</sqf:description>
				<sqf:replace match="akn:heading">
					<akn:heading>Schedules</akn:heading>
				</sqf:replace>
			</sqf:fix>
			<assert test="count(akn:hcontainer[@name='schedule']) gt 1 or empty(akn:heading)" sqf:fix="delete-schedules-heading">#drafting:There is only one schedule so there shouldn't be a "Schedules" heading</assert>
			<sqf:fix id="delete-schedules-heading">
				<sqf:description>
					<sqf:title>Delete the Schedules heading</sqf:title>
				</sqf:description>
				<sqf:delete match="akn:heading" />
			</sqf:fix>
		</rule>
	</pattern>

	<pattern id="schedule">
		<rule context="akn:hcontainer[@name='schedule']">

			<assert test="exists(akn:num)">#drafting:A schedule should start with a number</assert>
			<assert test="exists(akn:heading)">#drafting:A schedule should have a heading</assert>

			<let name="children" value="local:get-child-levels(.)" />
			<assert test="not(local:level-may-have-content(.) and empty($children) and empty(akn:content))">#drafting:A <value-of select="local:get-level-name(.)" /> should have content if not subdivided</assert>
			
			<assert test="exists(akn:intro) or empty(akn:wrapUp)">#drafting:There should be opening words to correspond to the closing words</assert>
			
			<assert test="count(distinct-values($children/local:get-level-name(.))) le 1">#drafting:A <value-of select="local:get-level-name(.)" /> should be evenly divided</assert>
			
			<let name="invalid-children" value="$children[not(local:levels-are-valid(current(), .))]" />
			<assert test="empty($invalid-children)">#drafting:A <value-of select="local:get-level-name(.)" /> should not contain a <value-of select="local:get-level-name($invalid-children[1])" /></assert>
		</rule>
		<rule context="akn:hcontainer[@name='schedule'][not(local:is-within-quoted-structure(.))]/akn:num">
			<let name="value" value="normalize-space(string-join(node()[not(self::akn:authorialNote)]/string(), ''))" />
			<assert test="exists(parent::*/preceding-sibling::akn:hcontainer[@name='schedule']) or exists(parent::*/following-sibling::akn:hcontainer[@name='schedule']) or ($value = 'Schedule')">#drafting:There is only one schedule so its number should be "Schedule"</assert>
			<assert test="exists(akn:authorialNote[@class='referenceNote'])">#drafting:There should be a reference to the section or sections that introduce the schedule</assert>
		</rule>
		<rule context="akn:authorialNote[@class='referenceNote']">
			<let name="value" value="normalize-space(lower-case(translate(., '()', '')))" />
			<assert test="not($is-scottish-act) or starts-with($value, 'introduced by ')">#drafting:The reference note should begin "Introduced by"</assert>
		</rule>
	</pattern>
	
	<pattern id="number">
		<rule context="akn:num">
			<assert test="normalize-space(.)">#drafting:The number should not be empty</assert>
		</rule>
	</pattern>
	
	<pattern id="heading">
		<rule context="akn:heading">
			<assert test="normalize-space(.)">#drafting:The heading should not be empty</assert>
		</rule>
	</pattern>
	
	<pattern id="content">
		<rule context="akn:content">
			<assert test="exists(*)" sqf:fix="add-content-p">#drafting:The content of a provision should not be empty</assert>
			<sqf:fix id="add-content-p">
				<sqf:description>
					<sqf:title>Add a content paragraph</sqf:title>
				</sqf:description>
				<sqf:add>
					<akn:p/>
				</sqf:add>
			</sqf:fix>
		</rule>
	</pattern>


	<!-- SI drafting rules -->
	
	<pattern id="si-banner">
		<rule context="akn:preface[$doc-type=$all-secondary-types]">
			<assert test="exists(akn:block[@name='banner'])">#drafting:The banner is missing</assert>
		</rule>
		<rule context="akn:block[@name='banner'][$doc-type='uksi']">
			<assert test="normalize-space(.) = 'STATUTORY INSTRUMENTS'">#drafting:The banner text of a UKSI should be 'STATUTORY INSTRUMENTS'</assert>
		</rule>
		<rule context="akn:block[@name='banner'][$doc-type='ukdsi']">
			<assert test="normalize-space(.) = 'DRAFT STATUTORY INSTRUMENTS'">#drafting:The banner text of a draft UKSI should be 'DRAFT STATUTORY INSTRUMENTS'</assert>
		</rule>
		<rule context="akn:block[@name='banner'][$doc-type='ssi']">
			<assert test="normalize-space(.) = 'SCOTTISH STATUTORY INSTRUMENTS'">#drafting:The banner text of an SSI should be 'SCOTTISH STATUTORY INSTRUMENTS'</assert>
		</rule>
		<rule context="akn:block[@name='banner'][$doc-type='sdsi']">
			<assert test="normalize-space(.) = 'DRAFT SCOTTISH STATUTORY INSTRUMENTS'">#drafting:The banner text of a draft SSI should be 'DRAFT SCOTTISH STATUTORY INSTRUMENTS'</assert>
		</rule>
	</pattern>
	<pattern id="si-title">
		<rule context="akn:preface/akn:block[@name='title'][$doc-type=$all-secondary-types]">
			<let name="title1" value="normalize-space(local:resolve(.))" />
			<let name="var-si-title" value="normalize-space(key('eId', 'varSITitle')/@showAs)" />
			<let name="title" value="if ($title1 = '') then $var-si-title else $title1" />
			<assert test="starts-with($title, 'The ') or starts-with($title, 'Act of ') or starts-with($title, 'House of ') or starts-with($title, 'Her Majesty''s') or starts-with($title, 'Her Majesty’s ')">#drafting:An SI's title must begin with "The", "Act of", "House of", or "Her Majesty's"</assert>
			<assert test="matches($title, ' \d{4}$')">#drafting:An SI's title must end with a year</assert>
		</rule>
	</pattern>
	<pattern id="si-number">
		<rule context="akn:preface[$doc-type=$secondary-types]">
			<assert test="exists(akn:block[@name='number'])">#preflight-mandatory:An SI must contain a number block</assert>
		</rule>
		<rule context="akn:preface/akn:block[@name='number'][$doc-type=$secondary-types]">
			<let name="value" value="normalize-space(local:resolve(.))" />
			<assert test="not($doc-type=$secondary-types and not(matches($value, '^\d{4} No\. \d{1,4}$')))">#preflight-mandatory:An SI number should be in the format "#### No. #"</assert>
			<assert test="not($doc-type=$draft-secondary-types and not(matches($value, '^\d{4} No\.$')))">#preflight-mandatory:A draft SI number should be in the format "#### No."</assert>
		</rule>
	</pattern>
	<pattern id="si-year">
		<let name="number-block" value="normalize-space(local:resolve(/akn:akomaNtoso/*/akn:preface/akn:block[@name='number']))" />
		<let name="title" value="normalize-space(local:resolve(/akn:akomaNtoso/*/akn:preface/akn:block[@name='title']))" />
		<let name="number-from-number-block" value="substring($number-block, 1, 4)" />
		<let name="number-from-title" value="substring($title, string-length($title) - 3)" />
		<let name="match" value="$number-from-number-block = $number-from-title" />
		<rule context="akn:preface/akn:block[@name='number'][$doc-type = $all-secondary-types]">
			<report test="false()">This SI's number is <value-of select="$number-block" /></report>
			<assert test="$match">#preflight-mandatory:The year in an SI's number must match the year in the SI's title (<value-of select="$number-from-number-block" />, <value-of select="$number-from-title" />)</assert>
		</rule>		
		<rule context="akn:preface/akn:block[@name='title'][$doc-type = $all-secondary-types]">
			<assert test="$match">#preflight-mandatory:The year in an SI's number must match the year in the SI's title (<value-of select="$number-from-number-block" />, <value-of select="$number-from-title" />)</assert>
		</rule>		
	</pattern>


	<!-- pre-flight rules (mandatory) -->

	<pattern id="two-or-more">
		<rule context="akn:body">
			<let name="children" value="*[not(local:is-p1(.))][not(self::akn:hcontainer[@name='schedules'])][not(self::akn:hcontainer[@name='signatures'])]" />
			<assert test="count($children) != 1">#preflight-mandatory:The body should contain two or more grouping levels</assert>
		</rule>
		<rule context="akn:*[local:is-level(.)] | akn:schedule">
			<let name="children" value="local:get-child-levels(.)[not(local:is-p1(.))]" />
			<assert test="count($children) != 1">#preflight-mandatory:A <value-of select="local:get-level-name(.)" /> should contain two or more child levels</assert>
		</rule>
	</pattern>
	<pattern id="all-internal-refs-exist">
		<rule context="akn:ref[starts-with(@href, '#')]">
			<let name="id" value="substring(@href, 2)" />
			<assert test="exists(key('eId', $id))">#preflight-mandatory:This reference points to an element that does not exist</assert>
		</rule>
	</pattern>
	
	<pattern id="si-preflight-signature">
		<rule context="akn:body[$doc-type = $all-secondary-types]">
			<assert test="exists(akn:hcontainer[@name='signatures'])">#preflight-mandatory:An SI must contain a signature block</assert>
		</rule>
		<rule context="akn:hcontainer[@name='signatureBlock']">
			<assert test="exists(akn:content/akn:block[@name='signature'])">#preflight-mandatory:A signature block must contain at least one signature</assert>
		</rule>
		<rule context="akn:hcontainer[@name='signature']">
			<assert test="exists(akn:block[@name='date'])">#preflight-mandatory:A signature block must contain at least one date line</assert>
		</rule>
		<rule context="akn:hcontainer[@name='signature']/akn:block[@name='date']">
			<assert test="exists(akn:date)">#preflight-mandatory:The date line must contain a date</assert>
		</rule>
	</pattern>
	<pattern id="made-date-signature-date">
		<rule context="akn:preface[$doc-type=$secondary-types]">
			<assert test="exists(akn:container[@name='dates'])">#preflight-mandatory:The preface should contain a dates container</assert>
		</rule>
		<rule context="akn:preface/akn:container[@name='dates'][$doc-type=$secondary-types]">
			<assert test="exists(akn:block[@name='madeDate'])">#preflight-mandatory:The dates container should contain a made date</assert>
		</rule>
		<rule context="akn:preface/akn:container[@name='dates']/akn:block[@name='madeDate'][$doc-type=$secondary-types]">
			<let name="attr-date" value="if (exists(akn:docDate/@date)) then xs:date(substring(akn:docDate/@date, 1, 10)) else ()" />
			<let name="var-date" value="xs:date(substring(key('eId', 'varMadeDate')/@showAs, 1, 10))" />
			<let name="all-sig-dates" value="/akn:akomaNtoso/*/akn:body/akn:hcontainer[@name='signatures']//akn:date" />
			<let name="last-sig-date" value="local:last-date($all-sig-dates)" />
			<assert test="exists($attr-date) and ($attr-date eq $last-sig-date)">#preflight-mandatory:The made date and signature dates must match</assert>
		</rule>
	</pattern>
	<pattern id="preflight-mandatory-misc">
		<rule context="akn:akomaNtoso/*">
			<assert test="empty(descendant::processing-instruction('oxy_insert_start')) and empty(descendant::processing-instruction('oxy_insert_end')) and empty(descendant::processing-instruction('oxy_delete'))">Track changes are not allowed in this document</assert>
		</rule>
		<rule context="akn:preface[$doc-type = $draft-secondary-types]">
			<assert test="exists(akn:block[@name='proceduralRubric'])">#preflight-mandatory:A draft SI should include a draft headnote</assert>
		</rule>
	</pattern>
	
	
	<!-- pre-flight rules (advisory) -->
	
	<pattern id="preflight-advisory-misc">
		<rule context="akn:preface/akn:block[@name='title']">
			<let name="title" value="local:resolve(.)" />
			<let name="opens" value="string-length(translate($title, '(', ''))" />
			<let name="closes" value="string-length(translate($title, ')', ''))" />
			<assert test="$opens = $closes">#preflight-advisory:There are an uneven number of brackets in the title</assert>
		</rule>
	</pattern>
	
	<pattern id="draft-si-not-laid">
		<rule context="akn:preface/akn:container[@name='dates']/akn:block[@name='laidDate']">
			<assert test="not($doc-type = $draft-secondary-types)">#preflight-advisory:A draft SI should not include a laid date</assert>
		</rule>
	</pattern>
	<pattern id="si-subjects">
		<rule context="akn:block[@name='subject'][$doc-type=('ssi','sdsi')]">
			<let name="subject" value="local:resolve(.)" />
			<assert test="not(ends-with($subject, ', SCOTLAND'))">#preflight-advisory:The subject in an SSI should not contain a Scotland extent suffix</assert>
		</rule>
		<rule context="akn:block[@name='subject'][$doc-type=('uksi','ukdsi')]">
			<let name="subject" value="local:resolve(.)" />
			<assert test="not(ends-with($subject, ', UNITED KINGDOM'))">#preflight-advisory:The subject in an UKSI should not contain a UK extent suffix</assert>
		</rule>
	</pattern>
	<pattern id="defs-alphabetical-order">
		<rule context="akn:hcontainer[@name='definition']">
			<let name="previous-term" value="preceding-sibling::akn:hcontainer[@name='definition'][1]/(descendant::akn:def)[1]" />
			<let name="this-term" value="(descendant::akn:def)[1]" />
			<assert test="local:are-in-alphabetical-order($previous-term, $this-term)">#preflight-advisory:Definitions should be listed in alphabetical order</assert>
		</rule>
	</pattern>
</schema>
