La structure des pattern

Jusqu'ici, nous n'avons présenté que des schémas Schematron contenant une règle unique. Il nous reste à faire connaissance avec le dernier élément inconnu de notre schéma, l'élément <pattern> qui entre en jeu lors de la configuration de plusieurs règles.

Fréquentes sources d'erreur: la structure des pattern

Dans la plupart des cas, on renonce à une structure spéciale et chaque règle est imbriquée dans son propre élément <pattern>. Les éléments <pattern> seront alignés à cette occasion. Les pattern ou les règles qu'ils contiennent sont égaux; comme pour les tests, aucune différence n'est opérée du fait de leur place dans le schéma. Par contre, plusieurs règles dans un élément <pattern> peuvent augmenter les performances du schéma. Une bonne pratique, un questionnement adéquat, ainsi qu'une bonne construction de l'alignement dans le pattern peuvent le rendre plus efficace. Mais tout d'abord, intéressons-nous aux possibles sources d'erreur:

<pattern>
  <rule context="arc:animal[@carnivore='oui']">
    <report test="parent::*/arc:animal[@carnivore='non']">
    Il y a des carnivores et des herbivores dans un même compartiment.
    Les animaux ne sont pas une ressource alimentaire!
    </report>
    <report test="parent::*/arc:animal/arc:poids &lt; (arc:poids div 2)">
    Noé, ce carnivore est trop fort (lourd) pour celui qui partage son compartiment. 
    Il pourrait l'utiliser comme ressource alimentaire.
    </report>
  </rule>
  <rule context="arc:animal">
    <report test="count (parent::*/arc:animal[arc:espece=current()/arc:espece]) &lt; 2">
    Il y a moins de deux animaux de cette espèce dans un compartiment.
    </report>
  </rule>
</pattern>

Il n'y a pas d'erreur fondamentale dans ce patron (pattern). Un patron peut tout-à-fait être constitué de plusieurs règles. Cependant, il faut noter que lors de l'analyse, la place des règles à l'intérieur d'un patron a son importance. 

 

Le principe suivant s'applique:
Dans un patron, chaque nœud de l'instance ne peut être choisie qu'une seule fois en tant que nœud de contexte d'une règle. Si un nœud correspond aux conditions de plusieurs règles d'un patron, il ne sera choisi en tant que nœud de contexte que pour la première des règles valables. Ce principe, somme toute complexe, peut être expliqué de façon imagée: Chaque règle d'un patron représente un tamis. Ces tamis seront placés les uns sur les autres dans le même ordre que celui des règles du patron. Les nœuds de l'instance seront alors secoués comme du sable au travers d'une cascade de tamis. Si un nœud correspond à une règle, autrement dit s'il ne passe pas au travers du tamis, il ne peut atteindre les autres tamis situés au dessous qui l'auraient également sélectionné.

 

Que signifie ceci pour le patron représenté ci-dessus?
Observons de plus près chacune des règles. Nous connaissons déjà la première. Elle sélectionne tous les animaux carnivores et vérifie si l'élément parent (<compartiment>) contient un animal qui ne mange pas de viande et si l'animal en question ne pourrait pas se révéler être un danger pour les autres.
La deuxième règle sélectionne tous les animaux. Le test s'assure que l'élément parent ne contient pas plus de deux animaux d'une même espèce (y compris l'animal sélectionné).
Cependant, si le principe du respect de l'alignement, cité ci-dessus, est inclus dans le patron, il en découle que la seconde règle ne passe pas de nouveau en revue tous les animaux. Puisque les animaux carnivores ont été choisis comme nœud de contexte par la première règle, la seconde ne vérifie plus que les herbivores. Toutefois, ceci ne va pas dans le sens de la règle. Si cette règle est prévue pour vérifier pour chaque animal, s'il y a plus d'une paire de chaque espèce, elle doit être transferée dans un pattern autonome:

<pattern>
  <rule context="arc:animal[@carnivore='oui']">
    <report test="parent::*/arc:animal[@carnivore='non']">
    Il y a des carnivores et des herbivores dans un même compartiment.
    Les animaux ne sont pas des ressources alimentaires!
    </report>
    <report test="parent::*/arc:animal/arc:poids &lt; (arc:poids div 2)">
    Noé, ce carnivore est trop fort (lourd) pour celui qui partage son
    compartiment. Il pourrait l'utiliser comme ressource alimentaire.
    </report>
  </rule>
</pattern>
<pattern>
  <rule context="arc:animal">
    <report test="count(parent::*/arc:animal[arc:espece=current()/arc:espece]) &lt; 2">
    Il se trouve moins de deux animaux de cette espèce dans ce compartiment.
    </report>
  </rule>
</pattern>

Copyright © dpunkt.verlag GmbH 2011
Vous pouvez imprimer cette version en ligne pour un usage privé. Par ailleurs, ce chapitre du livre "Schematron - Effiziente Business Rules für XML-Dokumente" est soumis aux mêmes clauses prévues pour la version papier : L'intégralité de l'oeuvre est protégée par les droits d'auteurs. Tous droits réservés y compris la copie, la traduction, la reproduction sur microfilm, tout comme l'enregistrement et le traitement dans des systèmes électroniques.

dpunkt.verlag GmbH, Ringstraße 19B, 69115 Heidelberg, téléphone + 49 (0)6221-14830, fax + 49 (0)6221-148399, hallo(at)dpunkt.de