<?xml version="1.0" encoding="UTF-8"?>
<!--***********************************************************************-->
<!-- TITLE       : METS Fedora Extension 1.1 Schematron Rules              -->
<!-- DESCRIPTION : This document expresses validation rules for Fedora     -->
<!--               objects encoded in METS Fedora Extension 1.1.           -->
<!--               These rules, when combined with the METS Fedora         -->
<!--               Extension 1.1 XSD Schema, can be used to fully validate -->
<!--               a METS Fedora Extension 1.1 XML document.               -->
<!-- CHANGELOG   : (1.0 to 1.1)                                            -->
<!--               o Removed disseminator-related rules (structMap, div,   -->
<!--                 behaviorSec) due to the CMDA.                         -->
<!--               o Changed xlink namespace to published 1999 version,    -->
<!--                 as this was done with METS after version 1.3.         -->
<!--               o Made TYPE attribute on root optional                  -->
<!--               o Removed rules governing existence of certain          -->
<!--                 datastreams in service definition & deployment        -->
<!--                 objects.  This should be handled by a separate        -->
<!--                 content model validator                               -->
<!--***********************************************************************-->
<sch:schema xmlns:sch="http://www.ascc.net/xml/schematron">
	<sch:ns prefix="METS" uri="http://www.loc.gov/METS/"/>
	<sch:ns prefix="xlink" uri="http://www.w3.org/1999/xlink"/>
	<sch:ns prefix="xsi" uri="http://www.w3.org/2001/XMLSchema-instance"/>
	<!-- VALIDATION FOR OBJECT INGEST PHASE:  These rules apply to a digital object in its "submission" format for ingest into the repository-->
	<!-- These rules are to be applied upon initial receipt of the object by the repository, before the repository has done any processing of the input.-->
	<sch:phase id="ingest">
		<sch:active pattern="preliminary"/>
	</sch:phase>
	<!-- VALIDATION FOR OBJECT STORAGE PHASE: Rules to ensure that digital object is FULLY valid before being accepted for final storage in the repository-->
	<!-- These rules are to be applied after all processing has been done by the repository, and before it is submitted to low level storage.-->
	<sch:phase id="store">
		<sch:active pattern="preliminary"/>
		<sch:active pattern="completed"/>
	</sch:phase>
	<!-- PRELIMINARY INGEST RULES PATTERN: -->
	<!-- These rules are to be applied to objects no matter what phase of the object lifecycle they are in.-->
	<sch:pattern name="Preliminary Object Checks" id="preliminary">
		<sch:rule context="METS:mets">
			<sch:assert test="string-length(@OBJID) &lt;= 64">Object PID must not exceed length of 64 (mets:mets OBJID)</sch:assert>
			<sch:assert test="not(@LABEL) or string-length(@LABEL) &lt;= 255">Object label must not exceed length of 255 (mets:mets LABEL)</sch:assert>
			<sch:report test="METS:dmdSec">The METS:dmdSec element is not supported by Fedora.   Use the METS:dmdSecFedora element instead (see the Fedora extension of the METS 1.0 schema)</sch:report>
		</sch:rule>
		<sch:rule context="METS:metsHdr">
			<sch:assert test="count(METS:agent) = 1 or count(METS:agent) = 0">Currently, Fedora will only support ONE agent</sch:assert>
		</sch:rule>
		<sch:rule context="METS:agent">
			<sch:assert test="@ROLE='IPOWNER'">Currently, Fedora will only support ONE agent with a role of IPOWNER</sch:assert>
		</sch:rule>
		<sch:rule context="METS:dmdSecFedora">
			<sch:assert test="@ID">Every Datastream must have a DatastreamID (mets:dmdSecFedora: ID is missing)</sch:assert>
			<sch:assert test="string-length(@ID) &lt;= 64">Datastream ID must not exceed length of 64 (mets:dmdSecFedora ID)</sch:assert>
		</sch:rule>
		<sch:rule context="METS:amdSec">
			<sch:assert test="@ID">Every Datastream must have a DatastreamID (mets:amdSec: ID is missing)</sch:assert>
			<sch:assert test="string-length(@ID) &lt;= 64">Datastream ID must not exceed length of 64 (mets:amdSecID)</sch:assert>
		</sch:rule>
		<sch:rule context="METS:descMD">
			<sch:assert test="@ID">Every Datastream must have a Datastream Version ID (mets:descMD: ID is missing)</sch:assert>
			<sch:assert test="string-length(@ID) &lt;= 69">Datastream Version ID must not exceed length of 69 (mets:descMD ID)</sch:assert>
		</sch:rule>
		<sch:rule context="METS:techMD">
			<sch:assert test="@ID">Every Datastream must have a Datastream Version ID (mets:techMD: ID is missing)</sch:assert>
			<sch:assert test="string-length(@ID) &lt;= 69">Datastream Version ID must not exceed length of 69 (mets:techMD ID)</sch:assert>
		</sch:rule>
		<sch:rule context="METS:rightsMD">
			<sch:assert test="@ID">Every Datastream must have a Datastream Version ID (mets:rightsMD: ID is missing)</sch:assert>
			<sch:assert test="string-length(@ID) &lt;= 69">Datastream Version ID must not exceed length of 69 (mets:rightsMD ID)</sch:assert>
		</sch:rule>
		<sch:rule context="METS:sourceMD">
			<sch:assert test="@ID">Every Datastream must have a Datastream Version ID (mets:sourceMD: ID is missing)</sch:assert>
			<sch:assert test="string-length(@ID) &lt;= 69">Datastream Version ID must not exceed length of 69 (mets:sourceMD ID)</sch:assert>
		</sch:rule>
		<sch:rule context="METS:digiprovMD">
			<sch:assert test="@ID">Every Datastream must have a Datastream Version ID (mets:digiprovMD: ID is missing)</sch:assert>
			<sch:assert test="string-length(@ID) &lt;= 69">Datastream Version ID must not exceed length of 69 (mets:digiprovMD ID)</sch:assert>
		</sch:rule>
		<sch:rule context="METS:mdWrap">
			<sch:assert test="not(@LABEL) or string-length(@LABEL) &lt;= 255">Datastream label must not exceed length of 255 (mets:mdWrap LABEL)</sch:assert>
			<sch:assert test="not(@CHECKSUM) or (@CHECKSUM and @CHECKSUMTYPE)">Datastream CHECKSUMTYPE must be specified if CHECKSUM is provided (mets:mdWrap: CHECKSUMTYPE missing or empty)</sch:assert>			
		</sch:rule>
		<sch:rule context="METS:fileSec">
			<sch:assert test="METS:fileGrp[@ID]">All Datastreams must have a DatastreamID (mets:fileGrp: ID is missing or empty)</sch:assert>
			<sch:assert test="METS:fileGrp[@ID='DATASTREAMS']">Datastreams section encoding error (mets:fileSec: must have child fileGrp whose ID is "DATASTREAMS"</sch:assert>
			<sch:assert test="count(METS:fileGrp) = 1">Datastreams section encoding error (mets:fileSec: can only have one fileGrp as direct decendant)</sch:assert>
		</sch:rule>
		<sch:rule context="METS:fileGrp">
			<sch:assert test="@ID">Every Datastream must have a DatastreamID (mets:fileGrp: ID is missing)</sch:assert>
			<sch:report test="contains(@ID, '+')">Datastream ID must not contain a plus sign (+) (mets:fileGrp: ID)</sch:report>
			<sch:report test="contains(@ID, ':')">Datastream ID must not contain a colon (:) (mets:fileGrp: ID)</sch:report>
			<sch:assert test="string-length(@ID) &lt;= 64">Datastream ID must not exceed length of 64 (mets:fileGrp ID)</sch:assert>
		</sch:rule>
		<sch:rule context="METS:file">
			<sch:assert test="@ID">Every Datastream must have a Datastream Version ID (mets:file: ID is missing)</sch:assert>
			<sch:report test="contains(@ID, '+')">Datastream version ID must not contain a plus sign (+) (mets:file: ID)</sch:report>
			<sch:report test="contains(@ID, ':')">Datastream version ID must not contain a colon (:) (mets:file: ID)</sch:report>
			<sch:assert test="string-length(@ID) &lt;= 69">Datastream Version ID must not exceed length of 69 (mets:file ID)</sch:assert>
			<sch:assert test="string(@OWNERID)">Datastream control group must be recorded (mets:file: OWNERID missing or empty)</sch:assert>
			<sch:assert test="@OWNERID='R' or @OWNERID = 'E' or @OWNERID = 'M' or @OWNERID = 'X'">Datastream control group must be "E" for External-Ref, "M" for Managed-Content, "R" for Redirect, or "X" for Inline-XML-Metadata.  (mets:file: OWNERID)</sch:assert>
			<sch:assert test="not(@CHECKSUM) or (@CHECKSUM and @CHECKSUMTYPE)">Datastream CHECKSUMTYPE must be specified if CHECKSUM is provided (mets:file: CHECKSUMTYPE missing or empty)</sch:assert>			
		</sch:rule>		
		<sch:rule context="METS:FLocat">
			<sch:assert test="not(@xlink:title) or string-length(@xlink:title) &lt;= 255">Datastream label must not exceed length of 255 (mets:FLocat xlink:title)</sch:assert>
        </sch:rule>
	</sch:pattern>
	<!-- COMPLETED RULES PATTERN: -->
	<!-- These rules are to be applied to objects when they are considered completed and ready to be stored persistently in the repository.-->
	<sch:pattern name="Completed Object Checks" id="completed">
		<sch:rule context="METS:metsHdr">
			<sch:assert test="@CREATEDATE">Object must have a date of creation (mets:header: CREATEDATE missing)</sch:assert>
			<sch:assert test="string(@RECORDSTATUS)">Object state must be recorded (mets:header: RECORDSTATUS missing or empty)</sch:assert>
			<sch:assert test="@RECORDSTATUS ='A' or @RECORDSTATUS ='I' or @RECORDSTATUS ='D'">Object state value is invalid  (mets:header: RECORDSTATUS must be "A|I|D")</sch:assert>
		</sch:rule>
		<sch:rule context="METS:file">
			<sch:assert test="string(@STATUS)">Datastream state must be recorded (mets:file: STATUS missing or empty)</sch:assert>
			<sch:assert test="@STATUS= 'A' or @STATUS= 'I' or @STATUS= 'D'">Datastream state must be "A" for Active, "I" for Inactive, or "D" for Deleted.  (mets:file: STATUS)</sch:assert>
		</sch:rule>	
		<sch:rule context="METS:amdSec">
			<sch:assert test="@ID">Inline Metadata Datastream must have an id (mets:amdSec: ID missing)</sch:assert>
			<sch:assert test="string(@STATUS)">Inline Metadata Datastream state must be recorded (mets:amdSec: STATUS missing or empty)</sch:assert>
			<sch:assert test="@STATUS= 'A' or @STATUS= 'I' or @STATUS= 'D'">Inline Metadata Datastream state must be "A" for Active, "I" for Inactive, or "D" for Deleted.  (mets:amdSec: STATUS)</sch:assert>
		</sch:rule>
		<sch:rule context="METS:dmdSecFedora">
			<sch:assert test="@ID">Inline Metadata Datastream must have an id (mets:dmdSecFedora: ID missing)</sch:assert>
			<sch:assert test="string(@STATUS)">Inline Metadata Datastream state must be recorded (mets:dmdSecFedora: STATUS missing or empty)</sch:assert>
			<sch:assert test="@STATUS= 'A' or @STATUS= 'I' or @STATUS= 'D'">Inline Metadata Datastream state must be "A" for Active, "I" for Inactive, or "D" for Deleted.  (mets:dmdSecFedora: STATUS)</sch:assert>
		</sch:rule>
		<sch:rule context="METS:descMD">
			<sch:assert test="@CREATED">Inline Metadata Datastream must have a date of creation (mets:descMD: CREATED missing)</sch:assert>
			<sch:assert test="@ID">Inline Metadata Datastream must have a version id (mets:descMD: ID missing)</sch:assert>
		</sch:rule>
		<sch:rule context="METS:techMD">
			<sch:assert test="@CREATED">Inline Metadata Datastream must have a date of creation (mets:techMD: CREATED missing)</sch:assert>
			<sch:assert test="@ID">Inline Metadata Datastream must have a version id (mets:techMD: ID missing)</sch:assert>
		</sch:rule>
		<sch:rule context="METS:rightsMD">
			<sch:assert test="@CREATED">Inline Metadata Datastream must have a date of creation (mets:rightsMD: CREATED missing)</sch:assert>
			<sch:assert test="@ID">Inline Metadata Datastream must have a version id (mets:rightsMD: ID missing)</sch:assert>
		</sch:rule>
		<sch:rule context="METS:sourceMD">
			<sch:assert test="@CREATED">Inline Metadata Datastream must have a date of creation (mets:sourceMD: CREATED missing)</sch:assert>
			<sch:assert test="@ID">Inline Metadata Datastream must have a version id (mets:sourceMD: ID missing)</sch:assert>
		</sch:rule>
		<sch:rule context="METS:digiprovMD">
			<sch:assert test="@CREATED">Inline Metadata Datastream must have a date of creation (mets:digiprovMD: CREATED missing)</sch:assert>
			<sch:assert test="@ID">Inline Metadata Datastream must have a version id (mets:digiprovMD: ID missing)</sch:assert>
		</sch:rule>
	</sch:pattern>
</sch:schema>
