This is the first real excursion into writing additional
XSLT. The current use of XSLT is to process the input Schematron
file using iso_svrl.xsl
. In order to introduce
our own diagnostics we have to write some appropriate XSLT. Note
that 2 does not require an
implementation to make use of this element, see ¶5.5.1. So the
processing order changes. I've created
diagnostics.xsl
which imports
iso_svrl.xsl
, hence adding the diagnostics
whilst retaining the rest of the Schematron processing, including
the SVRL output format. I've created another
requirement on the input file, that it has a desc
child element in each chapter,
describing the chapter. The modified input file
input.diag.xml
is shown in Example 5.1, “The input file modified for diagnostics, file input.diag.xml”
Example 5.1. The input file modified for diagnostics, file input.diag.xml
<?xml version="1.0" encoding="utf-8" ?> <doc> <chapter id="c1"> <title>chapter title</title> <desc>Chapter description</desc> <para>Chapter content</para> </chapter> <chapter id="c2"> <title>chapter title</title> <para>xx</para> <para>yy</para> <para>zz</para> </chapter> <chapter id="c3"> <title>chapter title</title> <desc>Chapter description</desc> <para>xx</para> <para>yy</para> <para>zz</para> </chapter> </doc>
As you can see, I've been remiss, and omitted the chapter 2
desc
element. We need the diagnostics to inform us which
chapter is in error. It is actually possible to do this with an
assert, but this way allows additional freedom for the user to add
output as needed.
The modified Schematron file, input.diag.sch
is shown in
Example 5.2, “The Schematron file for diagnostics, file input.diag.sch ”
Example 5.2. The Schematron file for diagnostics, file input.diag.sch
<?xml version="1.0" encoding="iso-8859-1"?> <iso:schema xmlns="http://purl.oclc.org/dsdl/schematron" xmlns:iso="http://purl.oclc.org/dsdl/schematron" xmlns:sch="http://www.ascc.net/xml/schematron" queryBinding='xslt2' schemaVersion="Rev 1.6"> <iso:title>Test ISO schematron file. Introduction mode </iso:title> <iso:pattern id="doc.checks"> <iso:title>checking an XXX document</iso:title> <iso:rule context="doc"> <iso:report test="chapter">Report date.<iso:value-of select="current-dateTime()"/></iso:report> </iso:rule> </iso:pattern> <iso:pattern id="chapter.checks"> <iso:title>Basic Chapter checks</iso:title> <iso:p>All chapter level checks. </iso:p> <iso:rule context="chapter"> <iso:assert test="title">Chapter should have a title</iso:assert> <iso:assert test="count(para) >= 1" >Chapters must have more than 1 paragraph</iso:assert> <iso:assert test="*[1][self::title]" >Title must be first child of chapter</iso:assert> <iso:assert test="@id">All chapters must have an ID attribute</iso:assert> <iso:assert test="desc" diagnostics="desc.diag">Descriptor</iso:assert> </iso:rule> </iso:pattern> <iso:diagnostics> <iso:diagnostic id="desc.diag">Descriptor missing from chapter <iso:value-of select="@id"/></iso:diagnostic> </iso:diagnostics> </iso:schema>
The changes to this relate to the assert
with test
set to desc. Instead of providing a diagnostic message directly, this
links out the the diagnostics
element,
which in turn contains a single diagnostic
(with a matching id
attribute ) child
whose output is used in the assert
for the
second chapter. I've added a reference to the id
(in the input.diag.xml
file) which is the unique identifier of the chapter in question. This
means we need to process these diagnostics in the newly introduced
stylesheet, diagnostics.xsl
.
The first command of the build file changes appropriately, to
call up the new stylesheet, diagnostics.xsl
instead of iso_svrl.xsl
. I'll leave you to do
that.
The new stylesheet, diagnostics.xsl
is
shown in Example 5.3, “The stylesheet for diagnostics, file diagnostics.xsl ”.
Example 5.3. The stylesheet for diagnostics, file diagnostics.xsl
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:axsl="http://www.w3.org/1999/XSL/TransformAlias" xmlns:iso="http://purl.oclc.org/dsdl/schematron" xmlns:svrl="http://purl.oclc.org/dsdl/svrl" version="1.0"> <xsl:import href="iso_svrl.xsl"/> <xsl:output method="xml" indent="yes" encoding="utf-8"/> <xsl:template match="iso:diagnostic[@id='desc.diag']"> <xsl:apply-templates mode="text"/> </xsl:template> </xsl:stylesheet>
Note the import of iso_svrl.xsl
is needed
for the majority of the processing. The other subtlety (well I missed
it), is that the children of the iso:diagnostic element need to be
processed in text mode.
If the above configuration is run, the output produced is as in Example 5.4, “The resultant output file for diagnostics ”
Example 5.4. The resultant output file for diagnostics
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <svrl:schematron-output xmlns:dp="http://www.dpawson.co.uk/ns#" xmlns:xs="http:/ /www.w3.org/2001/XMLSchema" xmlns:svrl="http://purl.oclc.org/dsdl/svrl" xmlns:sch="http://www.ascc.net/xml/schematron" xmlns:iso="http://purl.oclc.org/dsdl/schematron" xmlns:xsd="http://www.w3.org/2001/XMLSchema" title="Test ISO schematron file. Introduction mode " schemaVersion="ISO19757-3"> <svrl:ns-prefix-in-attribute-value uri="http://www.dpawson.co.uk/ns#" prefix="dp"/> <svrl:active-pattern name="checking an XXX document" id="doc.checks"/> <svrl:fired-rule context="doc"/> <svrl:successful-report test="chapter" location="/doc[1]"> <svrl:text>Report date.2007-01-22T10:09:42.278Z</svrl:text> </svrl:successful-report> <svrl:active-pattern name="Basic Chapter checks" id="chapter.checks"> <svrl:text>All chapter level checks. </svrl:text> </svrl:active-pattern> <svrl:fired-rule context="chapter"/> <svrl:fired-rule context="chapter"/> <svrl:failed-assert test="desc">Descriptor missing from chapter c2<svrl:text/> </svrl:failed-assert> <svrl:fired-rule context="chapter"/> </svrl:schematron-output>Done
Of note is the failed-assert
element,
which indicates the id of the chapter (we could just as easily have
output the chapter title) in question. Before moving on from
diagnostics, I mentioned that the source of an assertion failure could
be determined using the assert statement? I'll cover that now.
One of the command line parameters to run Schematron is "generate-paths=yes" (or no). What this does is add an attribute to the output indicating the point (in the main input file) at which the assertion failed. So the command line for this first transform might change to
$ java -mx250m -ms250m -cp .;\myjava;\myjava\saxon8.jar;\myjava\xercesImpl.jar \
net.sf.saxon.Transform -x org.apache.xerces.parsers.SAXParser -w1 \
-o tmp.xsl %1.sch diagnostics.xsl "generate-paths=yes" "diagnose=true"
As before the lines have been split using the backslash (\) for readability. The new paramater is used to add the additional output information. Repeating the above example with this addition changes the output as shown in Example 5.5, “The modified output file for diagnostics, when using generate-paths ”
Example 5.5. The modified output file for diagnostics, when using generate-paths
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <svrl:schematron-output xmlns:dp="http://www.dpawson.co.uk/ns#" xmlns:xs="http:/ /www.w3.org/2001/XMLSchema" xmlns:svrl="http://purl.oclc.org/dsdl/svrl" xmlns:sch="http://www.ascc.net/xml/schematron" xmlns:iso="http://purl.oclc.org/dsdl/schematron" xmlns:xsd="http://www.w3.org/2001/XMLSchema" title="Test ISO schematron file. Introduction mode " schemaVersion="ISO19757-3"> <svrl:ns-prefix-in-attribute-value uri="http://www.dpawson.co.uk/ns#" prefix= "dp"/> <svrl:active-pattern name="checking an XXX document" id="doc.checks"/> <svrl:fired-rule context="doc"/> <svrl:successful-report test="chapter" location="/doc[1]"> <svrl:text>Report date.2007-01-22T10:31:03.605Z</svrl:text> </svrl:successful-report> <svrl:active-pattern name="Basic Chapter checks" id="chapter.checks"> <svrl:text>All chapter level checks. </svrl:text> </svrl:active-pattern> <svrl:fired-rule context="chapter"/> <svrl:fired-rule context="chapter"/> <svrl:failed-assert test="desc" location="/doc[1]/chapter[2]" >Descriptor missing from chapter c2<svrl:text/> </svrl:failed-assert> <svrl:fired-rule context="chapter"/> </svrl:schematron-output>Done
Note the extra location
attribute
on the failed-assert
element? It specifies
exactly, using xpath notation, where the assertion triggered, in this
case it was on the second occurrence of the chapter element, which
(thankfully) is exactly where we know it is in error.