Chapter 5. Diagnostics

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> 1
  <para>Chapter content</para>
</chapter>

<chapter id="c2">                      2
<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>   3
  <para>xx</para>
  <para>yy</para>
  <para>zz</para>
</chapter>
</doc>


    

1 3

These two chapters have the desc element

2

This chapter is missing the desc element


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>     1
    </iso:rule>
  </iso:pattern>


<iso:diagnostics>
  <iso:diagnostic id="desc.diag">Descriptor missing from 
   chapter <iso:value-of select="@id"/></iso:diagnostic>     2
</iso:diagnostics>
</iso:schema>


    

1

The assertion references the diagnostic associated with this test

2

The diagnostic which is triggered, with an additional diagnostic output


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"/>  1

  <xsl:output method="xml" indent="yes" encoding="utf-8"/>
  
  <xsl:template match="iso:diagnostic[@id='desc.diag']">  2
        <xsl:apply-templates mode="text"/>
  </xsl:template>

</xsl:stylesheet>

    

1

This stylesheet imports (and overrides where matching) the templates in iso_svrl.xsl

2

The template used for the specific diagnostic, which then applies templates to any children, in text mode as required by iso_svrl.xsl


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/> 1
   </svrl:failed-assert>
   <svrl:fired-rule context="chapter"/>
</svrl:schematron-output>Done

    

1

The diagnostic is triggered due to the missing desc element.


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/> 1
   </svrl:failed-assert>
   <svrl:fired-rule context="chapter"/>
</svrl:schematron-output>Done
    

1

Note how the extra information is (or could be) useful in identifying exactly which chapter is missing the desc element. Simple in this case, but very useful on occasion.


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.

Legal Notice