Schematron-Regeln testen

Eine Schematron-Regel soll Fehler in XML-Dokumenten finden. Aber wer prüft, ob die Regel selbst richtig ist? Ein zu weit gefasster XPath oder ein vergessener Namensraum kann dazu führen, dass korrekte Dokumente abgewiesen werden oder echte Fehler unbemerkt bleiben. Mit XSpec lässt sich beides testen.

Dafür brauchen wir kleine Dokumente, bei denen das erwartete Verhalten klar ist: Hier muss eine Meldung kommen, dort darf keine kommen.

Ein Titel und ein Querverweis

Unser Beispiel hat zwei Regeln. Ein Artikel braucht einen nichtleeren Titel. Und ein xref muss auf ein vorhandenes Element mit passender xml:id zeigen. Das einfache Artikelmodell kommt ohne eigenen Namensraum aus und ist kein vollständiges Prüfprofil für JATS oder DocBook.

examples/06-schematron/article.sch

<?xml version="1.0" encoding="UTF-8"?>
<sch:schema xmlns:sch="http://purl.oclc.org/dsdl/schematron" queryBinding="xslt2">
  <sch:title>Editorial rules for a sample article</sch:title>
  <sch:ns prefix="xml" uri="http://www.w3.org/XML/1998/namespace"/>
  <sch:pattern id="editorial-rules">
    <sch:rule context="article">
      <sch:assert id="article-title" role="error"
        test="normalize-space(title) ne ''">An article must have a non-empty title.</sch:assert>
    </sch:rule>
    <sch:rule context="xref">
      <sch:assert id="xref-target" role="error"
        test="@rid = root(.)//*/@xml:id">A cross-reference must point to an existing ID.</sch:assert>
    </sch:rule>
  </sch:pattern>
</sch:schema>

Die Regeln haben die IDs article-title und xref-target. Darüber kann der Test sie gezielt ansprechen. Der Wortlaut einer Fehlermeldung lässt sich dann verbessern, ohne gleich den Test umbauen zu müssen.

Die Testsuite enthält einen korrekten Artikel sowie zwei getrennte Fehlerfälle: einen leeren Titel und einen Verweis ohne Ziel.

examples/06-schematron/article.xspec

<?xml version="1.0" encoding="UTF-8"?>
<x:description xmlns:x="http://www.jenitennison.com/xslt/xspec"
  schematron="article.sch">
  <x:scenario label="Accept a complete article">
    <x:context>
      <article><title>Testing XML</title><section xml:id="s1"/>
        <p>See <xref rid="s1"/>.</p></article>
    </x:context>
    <x:expect-valid/>
    <x:expect-not-assert id="article-title"/>
    <x:expect-not-assert id="xref-target"/>
  </x:scenario>
  <x:scenario label="Detect an empty title">
    <x:context><article><title>   </title></article></x:context>
    <x:expect-assert id="article-title"/>
    <x:expect-assert count="1"/>
  </x:scenario>
  <x:scenario label="Detect an unresolved cross-reference">
    <x:context><article><title>Testing XML</title><xref rid="missing"/></article></x:context>
    <x:expect-assert id="xref-target"/>
    <x:expect-not-assert id="article-title"/>
    <x:expect-assert count="1"/>
  </x:scenario>
</x:description>

Wann ist ein Schematron-Test bestanden?

x:expect-assert erwartet, dass eine verletzte Schematron-Assertion gemeldet wird. Das ist anfangs etwas ungewohnt: Ein bestandener XSpec-Test kann also genau darin bestehen, dass Schematron einen Fehler findet. Der Fehler wurde im Beispieldokument absichtlich eingebaut.

x:expect-not-assert prüft die andere Richtung: Diese Fehlermeldung darf nicht auftreten. Mit einer Regel-ID wird die gewünschte Meldung ausgewählt; mit count lässt sich ihre Anzahl kontrollieren. Beim kaputten Querverweis soll zum Beispiel nicht gleichzeitig ein Titelproblem gemeldet werden.

Ein Test nur mit fehlerhaften Dokumenten reicht nicht. Eine Regel, die jedes Dokument zurückweist, könnte dabei gut aussehen. Deshalb gehört zu jeder wichtigen Regel auch ein Beispiel, das akzeptiert werden muss.

x:expect-valid berücksichtigt die Rollen der Meldungen. Unsere Asserts tragen role="error". Für Warnungen und Informationen sollte ebenso festgelegt werden, welche Reaktion der Test erwartet.

Die Regeln ausführen

Mit dem Paket-Runner:

python scripts/run-tests.py --only schematron

Oder direkt im Schematron-Modus von XSpec:

"$XSPEC_HOME/bin/xspec.sh" -s -e -j examples/06-schematron/article.xspec

In der XSpec-4.0-Reihe wird für die XSLT-basierte Schematron-Verarbeitung SchXslt2 verwendet. XSpec 4.0.3 enthält SchXslt2 1.11.1. Beim Umstieg von einer alten Umgebung sollten deshalb auch der Compiler und seine Parameter geprüft werden, etwa die Auswahl von Phasen.

Für den Alltag reicht als Anfang oft ein kleines Set pro Regel: ein korrektes Dokument, der beabsichtigte Fehlerfall und ein ähnlicher Fall, der keinen Fehler auslösen darf. Große Bestände können später dazukommen. Die kleinen Beispiele machen meist schneller klar, warum etwas schiefgeht.

<< zurück                                                                                                             vor >>