← all demos
// ISO_SVRL.xsl
//
// Implementation of Schematron Validation Report Language from ISO Schematron
// ISO/IEC 19757 Document Schema Definition Languages (DSDL)
// Part 3: Rule-based validation  Schematron
// Annex D: Schematron Validation Report Language
//
// This ISO Standard is available free as a Publicly Available Specification in PDF from ISO.
// Also see www.schematron.com for drafts and other information.
//
// This implementation of SVRL is designed to run with the "Skeleton" implementation
// of Schematron which Oliver Becker devised. The skeleton code provides a
// Schematron implementation but with named templates for handling all output;
// the skeleton provides basic templates for output using this API, but client
// validators can be written to import the skeleton and override the default output
// templates as required. (In order to understand this, you must understand that
// a named template such as "process-assert" in this XSLT stylesheet overrides and
// replaces any template with the same name in the imported skeleton XSLT file.)
//
// The other important thing to understand in this code is that there are different
// versions of the Schematron skeleton. These track the development of Schematron through
// Schematron 1.5, Schematron 1.6 and now ISO Schematron. One only skeleton must be
// imported. The code has templates for the different skeletons commented out for
// convenience. ISO Schematron has a different namespace than Schematron 1.5 and 1.6;
// so the ISO Schematron skeleton has been written itself with an optional import
// statement to in turn import the Schematron 1.6 skeleton. This will allow you to
// validate with schemas from either namespace.
//
//
// History:
// 2010-07-10
// * MIT license
// 2010-04-14
// * Add command line parameter 'terminate' which will terminate on first failed
// assert and (optionally) successful report.
// 2009-03-18
// * Fix atrribute with space "see " which generates wrong name in some processors
// 2008-08-11
// * RJ Fix attribute/@select which saxon allows  in XSLT 1
// 2008-08-07
// * RJ Add output-encoding attribute to specify final encoding to use
// * Alter allow-foreign functionality so that Schematron span, emph and dir elements make
// it to the output, for better formatting and because span can be used to mark up
// semantically interesting information embedded in diagnostics, which reduces the
// need to extend SVRL itself
// * Diagnostic-reference had an invalid attribute @id that duplicated @diagnostic: removed
// 2008-08-06
// * RJ Fix invalid output:  svrl:diagnostic-reference is not contained in an svrl:text
// * Output comment to SVRL file giving filename if available (from command-line parameter)
// 2008-08-04
// * RJ move sch: prefix to schold: prefix to prevent confusion (we want people to
// be able to switch from old namespace to new namespace without changing the
// sch: prefix, so it is better to keep that prefix completely out of the XSLT)
// * Extra signature fixes (PH)
// 2008-08-03
// * Repair missing class parameter on process-p
// 2008-07-31
// * Update skeleton names
// 2007-04-03
// * Add option generate-fired-rule (RG)
// 2007-02-07
// * Prefer true|false for parameters. But allow yes|no on some old for compatability
// * DP Diagnostics output to svrl:text. Diagnosis put out after assertion text.
// * Removed non-SVRL elements and attributes: better handled as an extra layer that invokes this one
// * Add more formal parameters
// * Correct confusion between $schemaVersion and $queryBinding
// * Indent
// * Validate against RNC schemas for XSLT 1 and 2 (with regex tests removed)
// * Validate output with UniversalTest.sch against RNC schema for ISO SVRL
//
// 2007-02-01
// * DP. Update formal parameters of overriding named templates to handle more attributes.
// * DP. Refactor handling of rich and linkable parameters to a named template.
//
// 2007-01-22
// * DP change svrl:ns to svrl:ns-in-attribute-value
// * Change default when no queryBinding from "unknown" to "xslt"
//
// 2007-01-18:
// * Improve documentation
// * KH Add command-line options to generate paths or not
// * Use axsl:attribute rather than xsl:attribute to shut XSLT2 up
// * Add extra command-line options to pass to the iso_schematron_skeleton
//
// 2006-12-01: iso_svrl.xsl Rick Jelliffe,
// * update namespace,
// * update phase handling,
// * add flag param to process-assert and process-report & @ flag on output
//
// 2001: Conformance1-5.xsl Rick Jelliffe,
// * Created, using the skeleton code contributed by Oliver Becker
// Open Source Initiative OSI - The MIT License:Licensing
// [OSI Approved License]
//
// This source code was previously available under the zlib/libpng license.
// Attribution is polite.
//
// The MIT License
//
// Copyright (c) 2004-2010 Rick Jellife and Academia Sinica Computing Centre, Taiwan
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// Ideas nabbed from schematrons by Francis N., Miloslav N. and David C.
// The command-line parameters are:
// phase           NMTOKEN | "#ALL" (default) Select the phase for validation
// allow-foreign   "true" | "false" (default)   Pass non-Schematron elements  and rich markup  to the generated stylesheet
// diagnose= true | false|yes|no    Add the diagnostics to the assertion test in reports (yes|no are obsolete)
// generate-paths=true|false|yes|no   generate the @location attribute with XPaths (yes|no are obsolete)
// sch.exslt.imports semi-colon delimited string of filenames for some EXSLT implementations
// optimize        "visit-no-attributes"     Use only when the schema has no attributes as the context nodes
// generate-fired-rule "true"(default) | "false"  Generate fired-rule elements
// terminate= yes | no | true | false | assert  Terminate on the first failed assertion or successful report
// Note: whether any output at all is generated depends on the XSLT implementation.
xsl:stylesheet(
    version="1.0",
    xmlns:axsl="http://www.w3.org/1999/XSL/TransformAlias",
    xmlns:iso="http://purl.oclc.org/dsdl/schematron",
    xmlns:schold="http://www.ascc.net/xml/schematron",
    xmlns:svrl="http://purl.oclc.org/dsdl/svrl",
    xmlns:xs="http://www.w3.org/2001/XMLSchema",
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform")
  // Select the import statement and adjust the path as
  // necessary for your system.
  // If not XSLT2 then also remove svrl:active-pattern/@document="{document-uri()}" from process-pattern()
  // <xsl:import href="iso_schematron_skeleton_for_saxon.xsl"/>
  xsl:import(href="iso_schematron_skeleton_for_xslt1.xsl")
  // <xsl:import href="iso_schematron_skeleton.xsl"/>
  // <xsl:import href="skeleton1-5.xsl"/>
  // <xsl:import href="skeleton1-6.xsl"/>
  param diagnose := true
  param phase :=
    choose:
      // Handle Schematron 1.5 and 1.6 phases
      when //schold:schema/@defaultPhase:
        <- //schold:schema/@defaultPhase
      // Handle ISO Schematron phases
      when //iso:schema/@defaultPhase:
        <- //iso:schema/@defaultPhase
      else:
        "#ALL"
  param allow-foreign := false
  param generate-paths := true
  param generate-fired-rule := true
  param optimize
  param output-encoding
  // e.g. saxon file.xml file.xsl "sch.exslt.imports=.../string.xsl;.../math.xsl"
  param sch.exslt.imports
  // Experimental: If this file called, then must be generating svrl
  svrlTest := true()
  // ================================================================
  template process-prolog:
    axsl:output(indent="yes", method="xml", omit-xml-declaration="no", standalone="yes")
      if  string-length($output-encoding) > 0:
        @encoding
          <-  $output-encoding
  // Overrides skeleton.xsl
  template process-root:
    param title
    param contents
    param queryBinding := xslt1
    param schemaVersion
    param id
    param version
    // "Rich" parameters
    param fpi
    param icon
    param lang
    param see
    param space
    svrl:schematron-output(schemaVersion="{$schemaVersion}", title="{$title}")
      if  string-length( normalize-space( $phase )) > 0 and 
		not( normalize-space( $phase ) = '#ALL') :
        axsl:attribute(name="phase")
          <-  $phase 
      if  $allow-foreign = 'true':
      if  $allow-foreign = 'true':
        call richParms:
          fpi := $fpi
          icon := $icon
          lang := $lang
          see := $see
          space := $space
      axsl:comment
        axsl:value-of(select="$archiveDirParameter")
        axsl:value-of(select="$archiveNameParameter")
        axsl:value-of(select="$fileNameParameter")
        axsl:value-of(select="$fileDirParameter")
      apply
      copy $contents
  template process-assert(test, diagnostics, id, flag, role, subject, fpi, icon, lang, see, space):
    // "Linkable" parameters
    // "Rich" parameters
    svrl:failed-assert(test="{$test}")
      if string-length( $id ) > 0:
        axsl:attribute(name="id")
          <-  $id 
      if  string-length( $flag ) > 0:
        axsl:attribute(name="flag")
          <-  $flag 
      // Process rich attributes.
      call richParms:
        fpi := $fpi
        icon := $icon
        lang := $lang
        see := $see
        space := $space
      call linkableParms:
        role := $role
        subject := $subject
      if  $generate-paths = 'true' or $generate-paths= 'yes' :
        // true/false is the new way
        axsl:attribute(name="location")
          axsl:apply-templates(mode="schematron-get-full-path", select=".")
      svrl:text
        apply
      if $diagnose = 'yes' or $diagnose= 'true' :
        // true/false is the new way
        call diagnosticsSplit:
          str := $diagnostics
    if  $terminate = 'yes' or $terminate = 'true' :
      axsl:message(terminate="yes") = TERMINATING
    if  $terminate = 'assert' :
      axsl:message(terminate="yes") = TERMINATING
  template process-report(id, test, diagnostics, flag, role, subject, fpi, icon, lang, see, space):
    // "Linkable" parameters
    // "Rich" parameters
    svrl:successful-report(test="{$test}")
      if  string-length( $id ) > 0:
        axsl:attribute(name="id")
          <-  $id 
      if  string-length( $flag ) > 0:
        axsl:attribute(name="flag")
          <-  $flag 
      // Process rich attributes.
      call richParms:
        fpi := $fpi
        icon := $icon
        lang := $lang
        see := $see
        space := $space
      call linkableParms:
        role := $role
        subject := $subject
      if  $generate-paths = 'yes' or $generate-paths = 'true' :
        // true/false is the new way
        axsl:attribute(name="location")
          axsl:apply-templates(mode="schematron-get-full-path", select=".")
      svrl:text
        apply
      if $diagnose = 'yes' or $diagnose='true' :
        // true/false is the new way
        call diagnosticsSplit:
          str := $diagnostics
    if  $terminate = 'yes' or $terminate = 'true' :
      axsl:message(terminate="yes") = TERMINATING
  // Overrides skeleton
  template process-dir(value):
    choose:
      when  $allow-foreign = 'true':
        copy .
      else:
        // We generate too much whitespace rather than risking concatenation
        axsl:text
        apply
        axsl:text
  template process-diagnostic(id, fpi, icon, lang, see, space):
    // Rich parameters
    svrl:diagnostic-reference(diagnostic="{$id}")
      call richParms:
        fpi := $fpi
        icon := $icon
        lang := $lang
        see := $see
        space := $space
      apply
  // Overrides skeleton
  template process-emph(class):
    choose:
      when  $allow-foreign = 'true':
        copy .
      else:
        // We generate too much whitespace rather than risking concatenation
        axsl:text
        apply
        axsl:text
  template process-rule(id, context, flag, role, subject, fpi, icon, lang, see, space):
    // "Linkable" parameters
    // "Rich" parameters
    if  $generate-fired-rule = 'true':
      svrl:fired-rule(context="{$context}")
        // Process rich attributes.
        call richParms:
          fpi := $fpi
          icon := $icon
          lang := $lang
          see := $see
          space := $space
        if  string( $id ):
          @id
            <-  $id 
        if  string-length( $role ) > 0:
          @role
            <-  $role 
  template process-ns(prefix, uri):
    svrl:ns-prefix-in-attribute-values(prefix="{$prefix}", uri="{$uri}")
  template process-p(icon, class, id, lang):
    svrl:text
      apply
  template process-pattern(name, id, is-a, fpi, icon, lang, see, space):
    // "Rich" parameters
    svrl:active-pattern
      if  string( $id ):
        axsl:attribute(name="id")
          <-  $id 
      if  string( $name ):
        axsl:attribute(name="name")
          <-  $name 
      call richParms:
        fpi := $fpi
        icon := $icon
        lang := $lang
        see := $see
        space := $space
      // ?? report that this screws up iso:title processing
      apply
      // ?? Seems that this apply-templates is never triggered DP
      axsl:apply-templates
  // Overrides skeleton
  template process-message(pattern, role):
  // Overrides skeleton
  template process-span(class):
    choose:
      when  $allow-foreign = 'true':
        copy .
      else:
        // We generate too much whitespace rather than risking concatenation
        axsl:text
        apply
        axsl:text
  // ===========================================================================
  // processing rich parameters.
  template richParms(fpi, icon, lang, see, space):
    // "Rich" parameters
    // Process rich attributes.
    if  $allow-foreign = 'true':
      if string($fpi):
        axsl:attribute(name="fpi")
          <- $fpi
      if string($icon):
        axsl:attribute(name="icon")
          <- $icon
      if string($see):
        axsl:attribute(name="see")
          <- $see
    if string($space):
      axsl:attribute(name="xml:space")
        <- $space
    if string($lang):
      axsl:attribute(name="xml:lang")
        <- $lang
  // processing linkable parameters.
  template linkableParms(role, subject):
    // ISO SVRL has a role attribute to match the Schematron role attribute
    if  string($role ):
      axsl:attribute(name="role")
        <-  $role 
    // ISO SVRL does not have a subject attribute to match the Schematron subject attribute.
    // Instead, the Schematron subject attribute is folded into the location attribute