Chapter 7. Using keys for assertions

Sometimes it is useful to have the help of keys (as in xsl:keys) when tracking matches. My use came with this document. The html output is generated by using the id values of each chapter. So a chapter called keys.html will be derived from the chapter having xml:id value of keys. That's helpful and aids navigation. Except for the times when the author stops thinking. In a chapter about schemas I named the chapter schema, and also created a file, linked from that chapter, which also happened to be named schema.html

This is where keys come in. The validation requirement is to check if any chapter has an attribute xml:id, which is the same as an xlink:href attribute on a link element, which also has a .html extension. Clear? No, nor to me. A small example, the input document, see Example 7.1, “File input.keys.xml, showing a chapter and an xlink with matching names ”

Example 7.1. File input.keys.xml, showing a chapter and an xlink with matching names

<?xml version="1.0" encoding="utf-8" ?>
<doc xmlns:xlink="http://www.w3.org/1999/xlink">
<chapter xml:id="c1">
  <title>chapter title</title>
  <para>Chapter content</para>
</chapter>

<chapter xml:id="c2">
<title>chapter title</title>
<para>xx</para>
<para>yy</para>
<para>zz</para>
</chapter>

<chapter xml:id="c3">                                  1
  <para>Invalid first child of chapter</para>
  <title>chapter title</title>
  <para>xx</para>
  <para>yy</para>
  <para>This paragraph uses a link to a file called 
    <a xlink:href="c3.html">c3.html</a></para>   2
</chapter>
</doc>


1

The chapter id value (c3)

2

The externally referenced file with value c3.html


The processing system (docbook) will generate a file c3.html from the chapter, which will probably overwrite the other file with the same name, linked to from this chapter! Schematron and keys to the rescue.

The Schematron file (Example 7.2, “The Schematron file for the keys example.”) has two new features. Firstly another namespace declaration for prefix xlink, both in the document element and in the ns element. The xsl namespace is also added to the document element. Next, a key is defined, outside of any patterns, as required by annex C of the standard. Finally, the key is used in an assert statement.

Example 7.2. The Schematron file for the keys example.

  <?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:xlink="http://www.w3.org/1999/xlink"         1
	       xmlns:xsl="http://www.w3.org/1999/XSL/Transform"   2
	       queryBinding='xslt2'
	       schemaVersion="ISO19757-3">
  <iso:title>Test ISO schematron file. Introduction mode </iso:title>
  <iso:ns prefix='xlink' uri="http://www.w3.org/1999/xlink"/>  3

<!-- Define the key, anything in the xsl ns is copied through -->
<xsl:key name="href" match="a" use="@xlink:href"/>             4


<iso:pattern id="name.checks">
  <iso:title>Check for id names and linked names which are the same, excluding extension</iso:title>
  <iso:rule context="chapter[@xml:id]">
    <iso:assert test="not(key('href', concat(@xml:id, '.html')))">Warning.   5
    if chapter id value is used as html filename, there
    will be a conflict with <iso:value-of select="@xml:id"/>.html
    </iso:assert>
  </iso:rule>
</iso:pattern>
</iso:schema>

1 2

The xlink and xsl namespaces are declared for xml processing

3

The xlink namespace is declared for Schematron

4

The key is declared, matching all link elements, with the xlink:href attribute

5

Finally, the key is used to match against the xml:id attribute!


I hope that is clear. The principle is to check all links in the document (the a element), ensuring that the xlink:href value does not match the current xml:id value! When run (noting the error in the input file), the output is as Example 7.3, “The resulting output”

Example 7.3. The resulting output


<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<svrl:schematron-output xmlns:xlink="http://www.w3.org/1999/xlink"
                        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-values uri="http://www.w3.org/1999/xlink" prefix="xlink"/>
   <svrl:active-pattern name="Check for id names and linked names which are the same, excluding extension"
                        id="name.checks"/>
   <svrl:fired-rule context="chapter[@xml:id]"/>
   <svrl:fired-rule context="chapter[@xml:id]"/>
   <svrl:fired-rule context="chapter[@xml:id]"/>
   <svrl:failed-assert test="not(key('href', concat(@xml:id, '.html')))" location="/doc[1]/chapter[3]">
      <svrl:text>Warning. if chapter id value is used as html filename, there 1
    will be a conflict with c3.html
    </svrl:text>
      <svrl:text/>
   </svrl:failed-assert>
</svrl:schematron-output>

1

The error, nicely caught and identified.


Because of the power of keys, it is worth considering them for more complex cross referencing tasks

Be aware of where your keys are, and the restrictions regarding the use of keys with respect to one source file.

Of special note is the context in which the keys operate. The match attribute is with respect to the main document, not the schematron file? The use and name attributes are used as in XSLT.

Note

In the XSLT implementation mentioned here, keys are only allowed at the top level, just as in XSLT

Legal Notice