Die Pattern-Gliederung

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

Bisher wurden nur Schematron-Schemata vorgestellt, die eine einzelne Regel enthalten. Bei der Gliederung mehrerer Regeln kommt nun das letzte unbekannte Element aus unserem Schematron-Schema zum Einsatz: das <pattern>-Element.

Häufige Fehler bei der Pattern-Gliederung

In den meisten Fällen kann auf eine spezielle Gliederung verzichtet und jede Regel in ein eigenes <pattern>-Element geschachtelt werden. Dabei werden die <pattern>-Elemente aneinandergereiht. Die Pattern bzw. die darin enthaltenen Regeln sind dabei gleichberechtigt, und ähnlich wie bei den Tests gibt es keine funktionale Unterscheidung der Regeln aufgrund der Reihenfolge im Schema.
Mehrere Regeln in einem <pattern>-Element können dagegen die Performance des Schemas erhöhen und beim geübten Umgang und geeigneter Fehlerabfrage kann man mit durchdachter Gliederung die Reihenfolge in Patterns für einen funktionalen Zweck verwenden. Widmen wir uns aber zuerst der möglichen Fehlerquelle:

<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>
  <rule context="arc:tier">
    <report test="count (parent::*/arc:tier[arc:art=current()/arc:art]) &lt; 2">In dieser Unterkunft gibt es weniger als zwei Tiere dieser Art.</report>
  </rule>
</pattern>

An diesem Pattern ist grundlegend nichts falsch. Ein Pattern kann durchaus aus mehreren Regeln bestehen. Für die Analyse muss jedoch beachtet werden, dass innerhalb eines Patterns die Reihenfolge der Regeln eine Rolle spielt.

Es gilt der folgende Grundsatz:
Jeder Knoten der Instanz kann für ein Pattern nur einmal als Kontextknoten einer Regel ausgewählt werden. Trifft der Knoten auf die context-Bedingung mehrerer Regeln eines Patterns zu, wird der Knoten nur als Kontextknoten der ersten passenden Regel im Pattern ausgewählt.
Der etwas komplexe Grundsatz lässt sich auch bildlich veranschaulichen: Jede Regel eines Patterns stellt ein Sieb dar. Die Siebe werden in der gleichen Reihenfolge, wie die Regeln in dem Pattern vorkommen, übereinander aufgestellt. Die Knoten der Instanz werden nun wie Sand durch diese Sieb-Kaskade geschüttet. Passt ein Knoten auf eine Regel bzw. wird dieser vom Sieb nicht durchgelassen, kommt er gar nicht mehr zum weiter unten gelegenen Sieb, das den Knoten evtl. auch aussortiert hätte.

Was bedeutet das für das oben aufgeführte Pattern?
Betrachten wir erst einmal jede Regel für sich: Die erste Regel kennen wir bereits. Sie wählt alle fleischfressenden Tiere aus und prüft, ob das jeweilige Elternelement (<zimmer>) ein Tier enthält, das kein Fleischfresser ist, und ob das Tier nicht einem anderen Tier gefährlich werden könnte.
Die zweite Regel wählt alle Tiere aus. Der Test stellt sicher, dass das Elternelement nicht mehr als zwei Tiere dieser Art (inklusive dem ausgewählten) enthalten darf.
Wird jedoch der obige Grundsatz der Reihenfolge innerhalb von Patterns mit einbezogen, ergibt sich, dass die zweite Regel nicht mehr alle Tiere überprüft. Da Tiere, die Fleischfresser sind, von der ersten Regel als Kontextknoten ausgewählt werden, überprüft die zweite Regel nur noch alle pflanzenfressenden Tiere. Dies ist jedoch nicht im Sinne der Regel. Soll diese Regel – wie vorgesehen – für alle Tiere überprüfen, ob mehr als ein Paar vorhanden ist, muss sie in ein eigenständiges Pattern ausgelagert werden:

<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>
<pattern>
  <rule context="arc:tier">
    <report test="count(parent::*/arc:tier[arc:art=current()/arc:art]) &lt; 2">In dieser Unterkunft gibt es weniger als zwei Tiere dieser Art.</report>
  </rule>
</pattern>

   

<< 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