Chapitre 7. Schematron

7.1. Introduction

Schematron est un autre formalisme permettant de spécifier la structure d'un document XML. C'est donc au départ une alternative aux schémas mais il est plutôt complémentaire des schémas. Ce formalisme n'est pas très adapté pour définir l'imbrication des éléments comme le font les DTD ou les schémas en donnant une grammaire. En revanche, il permet d'imposer des contraintes sur le document qu'il est difficile, voire impossible, d'exprimer avec les schémas. Il est fréquent d'utiliser les deux formalismes conjointement. Un schéma définit la structure globale du document et un schematron la complète en ajoutant des contraintes supplémentaires que doit satisfaire le document pour être valide. Il existe d'ailleurs des mécanismes permettant d'inclure un schematron au sein d'un schéma.

Schematron est basé sur XPath. Un schematron est constitué de règles écrites avec des expressions XPath qui expriment la présence ou l'absence de motifs dans le document. Ce mécanisme rend schematron très puissant puisqu'il est possible de mettre en relation des éléments et des attributs qui sont éloignés dans le document. Schematron reste cependant très simple car le vocabulaire est restreint. L'écriture d'un schematron requiert l'utilisation de seulement quelques éléments.

7.2. Premier exemple

On donne ci-dessous un premier exemple de schematron très simple. Il contient une seule règle qui s'applique aux éléments list du document. Pour chacun de ces éléments, la valeur de l'attribut length doit être égale au nombre d'enfants.

<?xml version="1.0" encoding="utf-8"?>
<sch:schema xmlns:sch="http://purl.oclc.org/dsdl/schematron">1
  <sch:title>Premier exemple de schematron</sch:title>2
  <sch:pattern>
    <sch:rule context="list">3
      <sch:assert test="@length = count(*)">4
        L'attribut length doit être égal au nombre d'enfants.5
      </sch:assert>  
    </sch:rule>
  </sch:pattern>
</sch:schema>

1

Élément racine sch:schema du schematron avec la déclaration de l'espace de noms des schematrons.

2

Titre informatif du schematron.

3

Règle s'appliquant à tous les éléments list du document cible.

4

Contrainte proprement dite exprimée par une expression XPath.

5

Texte utilisé pour la fabrication du rapport.

Si le schematron précédent est appliqué au document XML suivant, le rapport va contenir le texte "L'attribut ... d'enfants." car la contrainte entre la valeur de l'attribut length et le nombre d'enfants de l'élément list n'est pas satisfaite par le deuxième élément list du document.

<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?>
<lists>
  <list length="3">
    <item>A</item><item>B</item><item>C</item>
  </list>
  <list length="4">
    <item>1</item><item>2</item><item>3</item>
  </list>
</lists>

Le résultat de la vérification du document ci-dessus avec le schematron donné précédemment est donné à la section suivante.

7.3. Fonctionnement

Le principe de fonctionnement de schematron est le suivant. Un document cible est validé avec un schematron en utilisant une application appropriée. Cette validation produit un rapport qui retrace les différentes étapes de la validation. Ce rapport contient des messages destinés à l'utilisateur. Ces messages peuvent provenir d'éventuelles erreurs mais ils peuvent aussi être positifs et confirmer que le document satisfait bien certaines contraintes. Ces différents messages sont produits par l'application de validation ou ils sont issus du schematron. Le schematron associe, en effet, des messages aux différentes contraintes qu'il contient. Ce rapport est souvent lui même un document XML.

La validation d'un document avec un schematron est souvent réalisée en deux phases. Dans une première phase, le schematron est transformé en une version compilée qui est indépendante du document. Dans une seconde phase, la version compilée est utilisée pour produire le rapport. La première phase est parfois, elle-même, scindée en plusieurs étapes afin de prendre en compte les règles et les blocs abstraits.

Validation avec un schematron

Figure 7.1. Validation avec un schematron


Il existe plusieurs implémentations de schematron souvent basées sur XSLT. Les deux phases sont réalisées par l'application de feuilles de style XSLT. Une première feuille de style XSLT transforme le schematron en une autre feuille de style XSLT qui constitue la version compilée du schematron. Cette dernière feuille de style est appliquée au document pour produire le rapport.

La composition exacte du rapport dépend de l'application qui réalise la validation du document avec le schematron. Il contient des fragments de texte issus du schematron mais aussi du texte produit par l'application de validation. Ce rapport peut être un simple fichier texte mais il est souvent un document XML, en particulier lorsque la validation est réalisée via XSLT. Le format SVRL est un dialecte XML conçu spécialement pour les rapports de validation avec des schematrons. Il est en particulier utilisé par l'implémentation standard de schematron disponible à l'adresse http://www.schematron.com/.

Le rapport SVRL obtenu par la validation du document XML avec le schematron donné ci-dessus est le suivant.

<?xml version="1.0" standalone="yes"?>
<svrl:schematron-output xmlns:svrl="http://purl.oclc.org/dsdl/svrl" 
                        xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
                        xmlns:sch="http://purl.oclc.org/dsdl/schematron" 
                        title="Comparaison attribut/nombre d'enfants" 
                        schemaVersion="ISO19757-3">
  <svrl:active-pattern/>
  <svrl:fired-rule context="list"/>
  <svrl:fired-rule context="list"/>
  <svrl:failed-assert test="@length = count(*)" location="/lists/list[2]">
    <svrl:text>L'attribut length doit être
               égal au nombre d'enfants.</svrl:text>
  </svrl:failed-assert>
</svrl:schematron-output>

7.4. Structure globale d'un schematron

L'ensemble d'un schematron est contenu dans un élément sch:schema. L'espace de noms des schematrons est identifié par l'URI http://purl.oclc.org/dsdl/schematron. Il existe des versions antérieures des schematrons qui utilisaient un autre espace de noms. Le préfixe généralement associé à l'espace de noms est sch comme dans cet ouvrage ou aussi iso pour bien distinguer la version ISO actuelle des schematrons des anciennes versions.

Un schematron est essentiellement constitué de règles regroupées en blocs. Il contient également du texte permettant de décrire les opérations effectuées. Il peut aussi déclarer des espaces de noms et des clés XSLT.

7.4.1. Espaces de noms cible

Lorsque les éléments des documents à valider appartiennent à un ou des espaces de noms, il est nécessaire de les déclarer dans le schematron et de leur associer des préfixes. Les préfixes sont nécessaires pour nommer correctement les éléments dans les expressions XPath des règles. Il faut en effet utiliser des noms qualifiés.

La déclaration d'un espace de noms se fait par l'élément sch:ns dont les attributs prefix et uri donnent respectivement le préfixe et l'URI qui identifie l'espace de noms.

<?xml version="1.0" encoding="utf-8"?>
<sch:schema queryBinding="xslt" schemaVersion="ISO19757-3"
            xmlns:sch="http://purl.oclc.org/dsdl/schematron">                  
  <sch:title>Comparaison attribut/nombre d'enfants</sch:title>
  <!-- Déclaration de l'espace de noms cible associé au prefix tns -->
  <sch:ns prefix="tns" uri="http://www.omega-one.org/~carton/"/>
  <sch:pattern>
    <!-- Le motif XPath utilise le nom qualifié de l'élément -->
    <sch:rule context="tns:list">                                  
      <sch:assert test="@length = count(*)">
        L'attribut length doit être égal au nombre d'éléments.
      </sch:assert>  
    </sch:rule>
  </sch:pattern>
</sch:schema>

7.4.2. Règles et blocs

Les règles d'un schematron sont regroupées en blocs. Chacun de ces blocs est introduit par un élément sch:pattern.

<?xml version="1.0" encoding="utf-8"?>
<sch:schema xmlns:sch="http://purl.oclc.org/dsdl/schematron">
  ...
  <sch:pattern>
    ...
  </sch:pattern>
  <sch:pattern>
    ...
  </sch:pattern>
  ...
</sch:schema>

Le contenu de chaque élément sch:pattern est composé de règles. Chaque règle est donnée par un élément sch:rule dont l'attribut context détermine à quels nœuds la règle s'applique. Chaque règle contient ensuite des tests introduits par les éléments sch:assert et sch:report.

<sch:pattern>
  <sch:rule context="...">
     ...
  </sch:rule>
  <sch:rule context="...">
     ...
  </sch:rule>
  ...
</sch:pattern>

La validation d'un document avec un schematron consiste à traiter séquentiellement chacun des blocs de règles. Pour chaque bloc et pour chaque nœud du document cible est déterminée la règle à appliquer. Les différents tests de cette règle sont réalisés et des messages sont ajoutés au rapport en fonction des résultats de ces tests. Même si plusieurs règles peuvent s'appliquer à un nœud, une seule des règles du bloc est réellement appliquée. Il faut donc éviter la situation où plusieurs règles d'un même bloc s'appliquent potentiellement à un même nœud.

7.4.3. Titres et commentaires

Le schematron ainsi que chacun de ses blocs peuvent être commentés. Les éléments sch:schema et sch:pattern peuvent avoir comme enfant un élément sch:title pour donner un titre. Ils peuvent aussi contenir des éléments sch:p prévus pour donner des descriptions plus détaillées. Les contenus des éléments sch:title et sch:p sont souvent repris pour la construction du rapport.

7.5. Règles

Chaque règle est matérialisée par un élément sch:rule qui contient un ou plusieurs tests. L'élément sch:rule possède un attribut context dont la valeur doit être un motif XPath. Ce motif détermine sur quels nœuds s'applique la règle.

Les tests d'une règle sont introduits par les éléments sch:assert et sch:report. Ces deux éléments prennent la même forme. Ils possèdent un attribut test dont la valeur est une expression XPath et ils contiennent du texte qui est éventuellement utilisé pour construire le rapport. Ces deux éléments se distinguent par leurs sémantiques qui sont à l'opposé l'une de l'autre.

<sch:rule context="...">
  <sch:assert test="...">
     ...
  </sch:assert>
  <sch:report test="...">
     ...
  </sch:report>
  ...
</sch:rule>

Un test introduit par sch:assert est réalisé de la façon suivante. L'expression XPath contenue dans l'attribut test est évaluée en prenant le nœud sélectionné comme contexte et le résultat de l'évaluation est converti en une valeur booléenne. Si le résultat est false, le texte contenu dans l'élément sch:assert est ajouté au rapport. Sinon rien n'est ajouté au rapport.

Dans l'exemple ci-dessous, le message d'erreur est ajouté au rapport si la condition n'est pas vérifiée, c'est-à-dire si l'élément book n'a aucun des attributs id ou key.

<sch:rule context="book">                                  
  <sch:assert test="@id|@key">
    L'élément book doit avoir un attribut id ou key
  </sch:assert>  
</sch:rule>

Un test introduit par sch:report est, au contraire, réalisé de la façon suivante. L'expression XPath contenue dans l'attribut test est évaluée en prenant le nœud sélectionné comme contexte et le résultat de l'évaluation est converti en une valeur booléenne. Si le résultat est true, le texte contenu dans l'élément sch:report est ajouté au rapport. Sinon rien n'est ajouté au rapport.

Dans l'exemple ci-dessous, le message d'erreur est ajouté au rapport si la condition est vérifiée, c'est-à-dire si l'élément book a simultanément les deux attributs id et key.

<sch:rule context="book">                                  
  <sch:report test="count(@id|@key) &gt; 1">
    L'élément book doit avoir un seul des attributs id ou key
  </sch:report>  
</sch:rule>

Chaque règle peut bien sûr contenir plusieurs éléments sch:assert et sch:report comme dans l'exemple ci-dessous. L'ordre de ces différents éléments est sans importance.

<sch:rule context="tns:pattern[@is-a]">                                  
  <sch:assert test="key('patid', @is-a)">
    L'attribut is-a doit référencer un bloc abstrait.
  </sch:assert>  
  <sch:report test="@abstract = 'true'">
    Un bloc avec un attribut is-a ne peut pas être abstrait.
  </sch:report>  
  <sch:report test="rule">
    Un bloc avec un attribut is-a ne peut pas contenir de règle.
  </sch:report>  
</sch:rule>

Le texte contenu dans les éléments sch:assert et sch:report peut aussi contenir des éléments sch:name et sch:value-of qui permettent d'ajouter du contenu dynamique. Lors de la construction du rapport, ces éléments sont évalués et ils sont remplacés par le résultat de leur évaluation. L'élément sch:name s'évalue en le nom de l'élément sur lequel est appliqué la règle. Il est particulièrement utile dans les règles abstraites et les blocs abstraits où le nom du contexte n'est pas fixé. L'élément sch:value-of a un attribut select contenant une expression XPath. L'évaluation de cette expression remplace l'élément sch:value-of dans le rapport. Un exemple d'utilisation de cet élément est donné à la section suivante.

7.5.1. Variables locales

Une règle peut définir des variables locales introduites par des éléments sch:let. Celles-ci mémorisent le résultat d'un calcul intermédiaire pour des utilisations dans la règle. Chaque élément sch:let a des attributs name et value pour spécifier le nom et la valeur de la variable. L'attribut value doit contenir une expression XPath qui donne sa valeur à la variable. Cette valeur ne peut plus ensuite être modifiée. Les éléments sch:let doivent être les premiers enfants de l'élément sch:rule. La variable ainsi déclarée est disponible dans toute la règle.

<?xml version="1.0" encoding="utf-8"?>
<sch:schema queryBinding="xslt" schemaVersion="ISO19757-3"
            xmlns:sch="http://purl.oclc.org/dsdl/schematron">                  
  <sch:title>Tests sur les heures</sch:title>
  <sch:pattern>
    <sch:rule context="time">
      <sch:let name="hour" value="number(substring(.,1,2))"/>
      <sch:let name="min"  value="number(substring(.,4,2))"/>
      <sch:let name="sec"  value="number(substring(.,7,2))"/>
      
      <!-- Test si l'heure est de la forme HH:MM:SS -->
      <sch:assert test="string-length(.) = 8 and substring(.,3,1) = ':' and 
                                                 substring(.,6,1) = ':'">
        L'heure <sch:value-of select="."/> doit être au format HH:MM:SS.
      </sch:assert>
      <sch:assert test="$hour >= 0 and $hour &lt;= 23">
        Le nombre d'heures doit être compris entre 0 et 23.
      </sch:assert>
      <sch:assert test="$min >= 0 and $min &lt;= 59">
        Le nombre de minutes doit être compris entre 0 et 59.
      </sch:assert>
      <sch:assert test="$sec >= 0 and $sec &lt;= 59">
        Le nombre de secondes doit être compris entre 0 et 59.
      </sch:assert>
    </sch:rule>  
  </sch:pattern>
</sch:schema>

7.6. Règles abstraites

Le principe général des règles abstraites est d'avoir des règles génériques susceptibles de s'appliquer à différents contextes. Le contexte d'une règle, c'est-à-dire l'ensemble des nœuds sur lesquels elle s'applique est normalement donné par son attribut context. Il est possible de définir une règle sans contexte qui définit seulement des contraintes. Elle ne peut pas être utilisée directement mais d'autres règles l'utilisent en spécifiant le contexte.

Une règle est déclarée abstraite avec un attribut abstract ayant la valeur true. Elle n'a pas d'attribut context. Elle possède, en revanche, un attribut id qui permet de la désigner pour l'utiliser. Une autre règle peut utiliser une règle abstraite en lui fournissant un contexte. Elle fait appel à la règle abstraite grâce à l'élément sch:extends dont l'attribut rule donne l'identifiant de la règle abstraite.

Dans l'exemple suivant une règle abstraite de nom has-title est définie. Elle vérifie que le nœud contexte possède un enfant title et que celui-ci est le premier enfant. Deux règles utilisent ensuite cette règle pour les éléments book et chapter.

<?xml version="1.0" encoding="utf-8"?>
<sch:schema queryBinding="xslt" schemaVersion="ISO19757-3"
            xmlns:sch="http://purl.oclc.org/dsdl/schematron">                  
  <sch:title>Utilisation de règles abstraites</sch:title>
  <sch:pattern>
    <!-- Règle abstraite qui teste si le premier enfant est title -->
    <sch:rule abstract="true" id="has-title">                                  
      <sch:assert test="*[1][self::title]">
        L'élément <sch:name/> doit avoir un enfant title qui 
        doit être le premier enfant.
      </sch:assert>  
    </sch:rule>
    <!-- Utilisation de la règle abstraite pour les éléments book -->
    <sch:rule context="book">                                  
      <sch:extends rule="has-title"/>
      <sch:assert test="chapter">
        Le livre soit contenir au moins un chapitre.
      </sch:assert>  
    </sch:rule>
    <!-- Utilisation de la règle abstraite pour les éléments chapter -->
    <sch:rule context="chapter">                                  
      <sch:extends rule="has-title"/>
      <sch:assert test="para">
        Le chapire soit contenir au moins un paragraphe.
      </sch:assert>  
    </sch:rule>
  </sch:pattern>
</sch:schema>

Ce schematron permet de vérifier que le document suivant n'est pas correct. L'élément title n'est pas le premier enfant du second chapter et le troisième chapter n'a pas d'enfant title.

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<book>
  <title>Titre du livre</title>
  <chapter>
    <title>Premier chapitre</title>
    <para>Ceci est le premier chapitre ...</para>
  </chapter>
  <chapter>
    <para>Paragraphe avant le titre ...</para>
    <title>Titre mal placé</title>
    <para>Second paragraphe du second chapitre après le titre ...</para>
  </chapter>
  <chapter>
    <para>Chapitre sans titre</para>
  </chapter>
</book>

7.7. Blocs abstraits

Les blocs abstraits généralisent le principe des règles abstraites. Ils déclarent des règles qui peuvent s'appliquer à différentes situations. Leur principe de fonctionnement est proche de celui des fonctions de n'importe quel langage de programmation. Un bloc abstrait contient des règles qui utilisent des paramètres. Ce bloc est alors utilisé par d'autres blocs qui instancient les paramètres en leur donnant des valeurs explicites.

Un bloc est déclaré abstrait avec un attribut abstract ayant la valeur true. Il a aussi un attribut id pour lui donner un identifiant. Le bloc qui utilise un bloc abstrait doit avoir un attribut is-a qui donne l'identifiant du bloc abstrait. Il ne doit pas contenir de règles mais seulement des éléments sch:param qui permettent d'instancier les paramètres. L'élément sch:param a des attributs name et value qui donnent respectivement le nom du paramètre et la valeur qui lui est affectée.

Le fonctionnement des blocs abstraits est semblable au passage de paramètres des éléments xsl:apply-templates et xsl:call-template de XSLT. En revanche, l'élément sch:param des schematrons est l'analogue de l'élément xsl:with-param de XSLT. L'élément xsl:param de XSLT n'a pas d'équivalent dans les schematrons car les paramètres des blocs abstraits ne sont pas déclarés.

Le schematron suivant définit un bloc abstrait de nom uniq qui contient deux règles dépendant des paramètres elem et desc. La première règle vérifie que l'élément elem a au moins un descendant desc. La seconde vérifie au contraire qu'il n'a pas plus d'un descendant desc. Ces deux règles conjuguées vérifient donc que l'élément elem a exactement un seul descendant desc.

Le bloc abstrait uniq est ensuite utilisé par les deux blocs uniq-id et uniq-title. Le premier bloc donne les valeurs book et @id|@key aux deux paramètres elem et desc. Il vérifie donc que chaque élément book possède exactement un seul des deux attributs id et key. Le second bloc donne les valeurs book et title aux paramètres elem et desc. Il vérifie donc que chaque élément book possède exactement un seul enfant title.

La vérification effectuée par le premier bloc n'est pas faisable avec les DTD et les schémas XML. Les déclarations d'attributs de ces deux langages se font sur chacun des attributs de façon indépendante. Il n'est pas possible d'exprimer une contrainte qui met en relation deux attributs ou deux éléments.

<?xml version="1.0" encoding="utf-8"?>
<sch:schema queryBinding="xslt" schemaVersion="ISO19757-3"
            xmlns:sch="http://purl.oclc.org/dsdl/schematron">                  
  <sch:title>Utilisation de blocs abstraits</sch:title>
  <!-- Déclaration du bloc abstrait -->
  <sch:pattern abstract="true" id="uniq">
    <!-- Les règles utilisent les paramètres elem et desc -->
    <sch:rule context="$elem">
      <sch:assert test="$desc">
        L'élément <sch:name/> doit avoir un descendant $desc.
      </sch:assert>  
      <sch:report test="count($desc) &gt; 1">
        L'élément <sch:name/> doit avoir un seul descendant $desc.
      </sch:report>  
    </sch:rule>
  </sch:pattern>
  <!-- Utilisation du bloc abstrait -->
  <sch:pattern is-a="uniq" id="uniq-id">
    <sch:param name="elem" value="book"/>
    <sch:param name="desc" value="@id|@key"/>
  </sch:pattern>
  <sch:pattern is-a="uniq" id="uniq-title">
    <sch:param name="elem" value="book"/>
    <sch:param name="desc" value="title"/>
  </sch:pattern>
</sch:schema>

Le mécanisme des blocs abstraits est souvent implémenté comme les #define du langage C. Chaque bloc qui utilise un bloc abstrait est remplacé par une copie de celui-ci où les paramètres sont substitués par leurs valeurs. Le schematron précédent est en fait équivalent au schematron suivant. Le bloc abstrait uniq a disparu mais ses règles apparaissent dupliquées dans les deux blocs uniq-id et uniq-title.

<?xml version="1.0" encoding="utf-8"?>
<sch:schema queryBinding="xslt" schemaVersion="ISO19757-3"
            xmlns:sch="http://purl.oclc.org/dsdl/schematron">                  
  <sch:title>Substitution des blocs abstraits</sch:title>
  <sch:pattern id="uniq-id">
    <sch:rule context="book">                                  
      <sch:assert test="@id|@key">
        L'élément <sch:name/> doit avoir un descendant @id|@key
      </sch:assert>  
      <sch:report test="count(@id|@key) &gt; 1">
        L'élément <sch:name/> doit avoir un seul descendant @id|@key
      </sch:report>  
    </sch:rule>
  </sch:pattern>
  <sch:pattern id="uniq-title">
    <sch:rule context="book">                                  
      <sch:assert test="title">
        L'élément <sch:name/> doit avoir un descendant title
      </sch:assert>  
      <sch:report test="count(title) &gt; 1">
        L'élément <sch:name/> doit avoir un seul descendant title
      </sch:report>  
    </sch:rule>
  </sch:pattern>
</sch:schema>

L'exemple ci-dessous illustre la puissance des schematrons. Ce schematron exprime certaines contraintes que doivent satisfaire les schematrons pour être valides. Ces contraintes portent sur les liens entre les éléments pattern abstraits et ceux qui les utilisent. Pour une meilleure efficacité, ce schématron utilise un index créé par l'élément XSLT xsl:key.

<?xml version="1.0" encoding="utf-8"?>
<sch:schema queryBinding="xslt" schemaVersion="ISO19757-3"
            xmlns:sch="http://purl.oclc.org/dsdl/schematron"  
            xmlns:xsl="http://www.w3.org/1999/XSL/Transform">                  
  <sch:title>Vérification des liens is-a des schematrons</sch:title>

  <sch:p>Ce schematron vérifie que, dans un schematron, tout bloc référencé
  par un autre bloc par l'attribut is-a est bien déclaré abstrait par
  l'attribut abstract avec la valeur true.</sch:p>
 
  <!-- Déclaration de l'espace de noms cible : celui des schematrons -->
  <!-- Ne pas utiliser le préfixe sch car cela pose problème -->
  <sch:ns prefix="tns" uri="http://purl.oclc.org/dsdl/schematron"/>

  <!-- Clé pour retrouver les éléments pattern par leur id -->
  <xsl:key name="patid" match="tns:pattern" use="@id"/> 

  <sch:pattern>
    <sch:rule context="tns:pattern[@is-a]">                                  
      <sch:assert test="key('patid', @is-a)">
        L'attribut is-a doit référencer un bloc abstrait.
      </sch:assert>  
      <sch:report test="@abstract = 'true'">
        Un bloc avec un attribut is-a ne peut pas être abstrait.
      </sch:report>  
      <sch:report test="rule">
        Un bloc avec un attribut is-a ne peut pas contenir de règle.
      </sch:report>  
    </sch:rule>
  </sch:pattern>
  <sch:pattern>
    <sch:rule context="tns:pattern[@abstract = 'true']">
      <sch:assert test="@id">
        Un bloc abstrait doit avoir un attribut id.
      </sch:assert>  
      <sch:report test="@is-a">
        Un bloc abstrait ne peut pas avoir un attribut is-a.
      </sch:report>
    </sch:rule>
  </sch:pattern>
</sch:schema>

7.8. Phases de validations

Il est possible de regrouper les blocs en phases. Chaque phase est identifiée par un nom. Lors de la validation d'un document par un schematron, il est possible de spécifier la phase à effectuer. Seuls les blocs appartenant à cette phase sont alors pris en compte. Ce mécanisme permet de scinder un schematron en plusieurs parties et de procéder à une validation incrémentale d'un document. Chaque phase déclare les blocs qu'elle contient et un bloc peut appartenir à plusieurs phases. Lorsque la validation par schematron est implémentée avec XSLT, la phase est précisée en donnant un paramètre global à la feuille de style XSLT. Il existe une phase par défaut appelée #ALL qui comprend tous les blocs. Si aucune phase n'est spécifiée, la validation utilise tous les blocs du schematron.

Une phase est déclarée par un élément sch:phase ayant un attribut id permettant de l'identifier. Chaque bloc de cette phase est donné par un enfant sch:active ayant un attribut pattern qui précise l'identifiant du bloc.

Dans l'exemple minimal ci-dessous, il y a deux phases appelées phase1 et phase2. Chacune de ces deux phases contient un seul bloc.

<?xml version="1.0" encoding="utf-8"?>
<sch:schema queryBinding="xslt" schemaVersion="ISO19757-3"
            xmlns:sch="http://purl.oclc.org/dsdl/schematron">                  
  <sch:title>Utilisation de phases</sch:title>

  <!-- Phase 1 ne comprenant que le premier bloc -->
  <sch:phase id="phase1">
    <sch:active pattern="idkey"/>
  </sch:phase>
  <!-- Phase 2 ne comprenant que le second bloc -->
  <sch:phase id="phase2">
    <sch:active pattern="count"/>
  </sch:phase>
  <!-- Vérification des attributs id et key -->
  <sch:pattern id="idkey">
    <sch:rule context="book">                                  
      <sch:assert test="@id|@key">
        L'élément book doit avoir un attribut id ou key
      </sch:assert>  
    </sch:rule>
  </sch:pattern>
  <!-- Décompte du nombre de livres -->
  <sch:pattern id="count">
    <sch:rule context="bibliography">                                  
      <sch:report test="book">
        Il y a <sch:value-of select="count(book)"/> livre(s).
      </sch:report>  
    </sch:rule>
  </sch:pattern>
</sch:schema>