Abstrakte Regeln

(Auszug aus "Schematron - Effiziente Business Rules für XML-Dokumente", Kapitel 7)

Eine weitere modulare Struktur in Schematron ist die der abstrakten Regel. Eine Schematron-Regel, die als abstrakt gekennzeichnet wird, unterscheidet sich von einer konkreten Regel dadurch, dass sie keinen Kontextknoten besitzt. Es handelt sich also um eine allgemeine Sammlung an Tests. Eine abstrakte Regel kann jedoch von einer konkreten Regel aufgerufen bzw. instanziiert werden.

So können verschiedene Kontextknoten anhand einer zentralen Testsammlung überprüft werden, wie folgendes Beispiel zeigt:

<rule context="arc:tier">
  <extends rule="gewicht"/>   (1)
<rule>
<rule abstract="true" id="gewicht">   (2)
  <report test="parent::*/arc:tier/arc:gewicht &amp;lt; (arc:gewicht div 10)">Noah, das Tier ist zu schwer für seine Zimmergenossen! Es könnte einen zertrampeln.</report>
</rule>

(1) Mit dem <extends>-Element wird eine abstrakte Regel referenziert. Dabei wird dem rule-Attribut die ID der abstrakten Regel (gewicht) übergeben. Der Kontext wird nun von der konkreten Regel auf die abstrakte Regel übertragen.

(2) Zur Erzeugung einer abstrakten Regel wird dem <rule>-Element ein abstract-Attribut mit dem Wert true mitgegeben. Eine abstrakte Regel benötigt immer ein id-Attribut als Referenz. In diesem Beispiel wird die ID gewicht vergeben.

Bisher hat diese Schreibweise allerdings noch keinen Mehrwert: Die abstrakte Regel wird noch nicht mehrfach verwendet. Daher benötigen wir eine weitere Regel, die den gleichen Test referenziert. Aus

<Pattern>
  <rule context="arc:tier[@fleischfresser='ja']">
    <report test="parent::*/arc:tier[@fleischfresser='nein']">Es gibt Fleischfresser und Pflanzenfresser in einer Unterkunft. Die Tiere sind keine Nahrungsquelle!</report>
    <report test="parent::*/arc:tier/arc:gewicht &lt; (arc:gewicht div 2)">Noah, dieser Fleischfresser ist zu stark (schwer) für seinen Zimmergenossen. Er könnte ihn als Nahrungsquelle benutzen.</report>
  </rule>
  […]
</pattern>

wird

<pattern>
  <rule context="arc:tier[@fleischfresser='ja']">
    <report test="parent::*/arc:tier[@fleischfresser='nein']">Es gibt Fleischfresser und Pflanzenfresser in einer Unterkunft. Die Tiere sind keine Nahrungsquelle!</report>
      <extends rule="gewicht"/>   (1)
  </rule>
  <rule context="arc:tier">
    <extends rule="gewicht"/>
  </rule>
  <rule abstract="true" id="gewicht">
    <report test="parent::*/arc:tier/arc:gewicht &lt; (arc:gewicht div 10)">Noah, das Tier ist zu schwer für seine Zimmergenossen! Es könnte einen zertrampeln.</report>
  </rule>
</pattern>

(1) In eine konkrete Regel, die andere Tests enthält, kann nun auch eine abstrakte Regel integriert werden.

Die Einsparung bei der Formulierung der Regel hat jedoch auch Auswirkungen auf die Regel selbst. Schließlich sollen fleischfressende Tiere maximal doppelt so schwer sein dürfen wie ihre Zimmergenossen. Nach dieser Abfrage sind jedoch auch zehnmal so schwere Fleischfresser erlaubt, da die Funktion des Tests für die Pflanzenfresser vollständig übernommen wurde.

Für einen solchen Fall kann eine abstrakte Regel mit Hilfe von Variablen parametrisiert werden. Hierzu wird in jeder konkreten Regel, die die abstrakte Regel aufruft, eine Variable mit gleichem Namen erzeugt, die innerhalb der abstrakten Regel verwendet werden kann, wie folgendes Beispiel zeigt:

<pattern>
  <rule context="arc:tier[@fleischfresser='ja']">
    <let name="faktor" value="2"/>   (1)
    <report test="parent::*/arc:tier[@fleischfresser='nein']">
    Es gibt Fleischfresser und Pflanzenfresser in einer Unterkunft. 
    Die Tiere sind keine Nahrungsquelle!</report>
    <extends rule="gewicht"/>
  </rule>
  <rule context="arc:tier">
    <let name="faktor" value="10"/>   (1)
    <extends rule="gewicht"/>
  </rule>
  <rule abstract="true" id="gewicht">
    <report test="parent::*/arc:tier/arc:gewicht &lt; (arc:gewicht div $faktor)">   (2)
    Noah, das Tier ist zu schwer für seine Zimmergenossen! Es könnte 
    einen zertrampeln bzw. als Nahrungsquelle benutzen. Dieses Tier 
    darf maximal <value-of select="$faktor"/>-mal so schwer sein, wie 
    der schwächste Zimmergenosse.</report>   (3)
  </rule>
</pattern>

(1) Innerhalb der Regel für Fleischfresser wird die Variable $faktor mit dem Wert 2 belegt. In der darauf folgenden Regel erhält die gleiche Variable den Wert 10. Wichtig ist, dass in allen Regeln, in denen die abstrakte Regel aufgerufen wird, eine Variable mit dem Namen faktor deklariert wird, da sie sonst in der abstrakten Regel nicht verwendet werden kann.

(2) In den ursprünglichen Varianten der Regel wurde für den hier abstrahierten Test jeweils die XPath-Abfrage parent::*/arc:tier/arc:gewicht &lt; (arc:gewicht div X) verwendet. An der Stelle, an der hier ein X steht, unterscheiden sich die Abfragen in den beiden Regeln: In der ersten Regel wird der Wert 10, in der zweiten Regel der Wert 2 verwendet.

(3) Da nun unterschiedliche Regeln die gleiche Fehlermeldung erzeugen, sollte diese nun allgemeiner formuliert werden. Die Verwendung einer Variable kann hier weiterhelfen.

   

<< zurück vor >>

 

 

 

Tipp der data2type-Redaktion:
Zum Thema Schematron bieten wir auch folgende Schulungen zur Vertiefung und professionellen Fortbildung an:

Copyright © dpunkt.verlag GmbH 2011
Für Ihren privaten Gebrauch dürfen Sie die Online-Version ausdrucken. Ansonsten unterliegt dieses Kapitel aus dem Buch "Schematron - Effiziente Business Rules für XML-Dokumente" denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

dpunkt.verlag GmbH, Ringstraße 19B, 69115 Heidelberg, fon 06221-14830, fax 06221-148399, hallo(at)dpunkt.de