Pour une utilisation efficace des pattern

Afin d'illustrer nos propos, nous remplacerons le second pattern dans l'exemple suivant:

<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>
</pattern>
<pattern>
  <rule context="arc:animal">
    <report test="parent::*/arc:animal/arc:poids &lt; (arc:poids div 10)">
    Noé, cet animal est trop lourd par rapport à ceux qui partage son compartiment!
    Il pourrait en piétiner un.
    </report>
  </rule>
</pattern>

La règle du second pattern vérifie pour tous les éléments <animal>, s'ils ne sont pas signicativement plus lourds que leurs compagnons de compartiment. La condition suivante s'applique ici: un animal ne peut être que dix fois plus lourd que le plus léger de ces compagnons de compartiment.
On peut d'emblée constater la ressemblance entre ce test et le second test de la règle. La question posée est la même, si ce n'est que le critère concernant la règle des carnivores est plus sévère: Un carnivore ne doit être, maximum, que deux fois plus lourd que ses compagnons de compartiment, alors que les autres animaux peuvent être jusqu'à dix fois plus lourd que les leurs.
En bref, un animal qui réussit le test de la règle des carnivores, réussit également celui de la nouvelle règle. Une nouvelle vérification des carnivores à l'aide de la seconde règle est par conséquent superflue et cette nouvelle règle pourrait aussi seulement examiner les non-carnivores:

<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>
</pattern>
<pattern>
  <rule context=" arc:animal[@carnivore='non']">
    <report test="parent::*/arc:animal/arc:poids &lt; (arc:poids div 10)">
    Noé, cet animal est trop lourd pour ceux qui partagent son compartiment!
    Il pourrait en piétiner un.
    </report>
  </rule>
</pattern>

Cette version présente le risque que l'instance, par exemple, puisse être complétée par une autre valeur en ce qui concerne l'attribut carnivore. Si des végétaliens, ayant la valeur vegetalien, sont accueillis dans l'instance, ils ne seront examinés par aucune des deux règles. L'erreur qui en découle sera corrigée grâce à la condition [not(@carnivore='oui')], utilisée à la place de [@carnivore='non']. Il existe cependant une méthode plus élégante et plus performante, pour structurer les deux règles dans un pattern:

<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>
  <rule context="arc:animal">
    <report test="parent::*/arc:animal/arc:poids &lt; (arc:poids div 10)">
    Noé, cet animal est trop lourd par rapport à ceux qui partagent son compartiment!
    Il pourrait en piétiner un.
    </report>
  </rule>
</pattern>

Lorsque les deux règles figurent dans un pattern, on peut profiter de leur ordre d'alignement: chaque élément <animal> qui a été choisi comme nœud de contexte dans la première règle, ne sera pas vérifié de nouveau dans la seconde. Tous les autres animaux, c'est-à-dire tous les animaux qui ne sont pas carnivores, seront examinés dans la seconde règle. C'est pourquoi, on peut se passer ici d'autres conditions en ce qui concerne l'élément <animal> qui sera choisi.
Deux règles sont plus efficaces dans un pattern, car le parseur doit parcourir une fois pour chaque pattern l'ensemble de l'arborescence de l'instance et vérifier pour chaque nœud, s'il correspond à l'une des règles données. Nous reparlerons de la structure du pattern lors de l'évocation de l'élément <phase>.

Remarque à l'attention des experts XSLT:
Pour les connaisseurs de XSLT, nous voulons jeter un coup d'oeil dans les coulisses. Une implémentation XSLT réalise un schéma Schematron avec deux pattern:

<xsl:template match="/">
  <xsl:apply-templates mode="P1"/>                                              (1)
  <xsl:apply-templates mode="P2"/>                                              (1)
</xsl:template>
<xsl:template match="arc:animal[@carnivore='oui']" mode="P1">                   (2)
  <xsl:if test="parent::*/arc:animal[@carnivore='non']">
    <!-- Conversion du message d'erreur -->
  </xsl:if>
  <xsl:if test="parent::*/arc:animal/arc:poids &lt; (arc:poids div 2)">
    <!-- Convertion du message d'erreur -->
  </xsl:if>
</xsl:template>
<xsl:template match="arc:animal[@carnivore='non']" mode="P2">                   (2)
  <xsl:if test="parent::*/arc:animal/arc:poids &lt; (arc:poids div 10)">
    <!-- Convertion du message d'erreur -->
  </xsl:if>
</xsl:template>
(1) Une commande <xsl:apply-templates> sera exécutée pour chaque pattern dans un mode propre.
(2) Un <xsl:template> particulier sera généré pour le mode respectif de chaque règle.

À titre de comparaison, voyez ci-dessous, comment une implémentation réalise la solution d'un pattern unique:

<xsl:template match="/">
  <xsl:apply-templates mode="P1"/>                                               (1)
</xsl:template>
<xsl:template match="arc:animal[@carnivore='oui']" priority="100" mode="P1">     (2)
  <xsl:if test="parent::*/arc:animal[@carnival='non']">
    <!-- Conversion du message d'erreur -->
  </xsl:if>
  <xsl:if test="parent::*/arc:animal/arc:poids &lt; (arc:poids div 2)">
    <!-- Conversion du message d'erreur -->
  </xsl:if>
</xsl:template>
<xsl:template match="arc:animal" priority="99" mode="P1">                        (2)
  <xsl:if test="parent::*/arc:animal/arc:poids &lt; (arc:poids div 10)">
    <!-- Conversion du message d'erreur -->
  </xsl:if>
</xsl:template>
(1) À cause de l'absence de patron, la seconde commande <xsl:apply-templates> est supprimée.
(2) Les templates sont également dans le même mode, car les deux règles figurent maintenant dans le même pattern. Lorsque plusieurs règles ou templates peuvent s'appliquer à un nœud, un conflit se produit. On le résout grâce à l'attribut priority qui est généré en fonction de l'ordre d'alignement des règles. Ceci démontre, pourquoi les nœuds qui conviennent à une règle, ne seront pas vérifiés en se fondant sur une autre règle dans le même pattern.

 

Vous avez désormais une connaissance approfondie de l'implémentation Skeleton. Le tableau suivant vous offre une vue d'ensemble de la transformation d'une construction Schematron en un élément XSL:

Schematron XSLT
<assert test="XPath">message d´erreur
</assert>
<xsl:choose>
<xsl:when test="XPath"/>
<xsl:otherwise>message d´erreur 
</xsl:otherwise>
</xsl:choose>
<report test="XPath">message d´erreur
</report>
<xsl:if test="XPath">message d´erreur
</xsl:if>
<rule context="XPath"> <xsl:template match="XPath"
priority="xxx" mode="Pattern-ID">
<pattern> <xsl:apply-templates select="/"
mode="Pattern-ID"/>
<< précédent suivant >>

 

 

 


 

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


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