Testing Schematron with Text Nodes - xspec/xspec GitHub Wiki

This page pertains to XSpec v2.3.2 and earlier. When using v3.0.3 and later, you will not see the failures in the example below and do not need the workaround.

Schematron does not visit text nodes by default when running XSpec v2.3.2 and earlier

Suppose you have this Schematron schema containing <sch:rule context="text()">:

test.sch

<sch:schema queryBinding="xslt2" xmlns:sch="http://purl.oclc.org/dsdl/schematron">
    <sch:pattern>
        <sch:rule context="text()">
            <sch:report id="above-mentioned" role="info" test="matches(., 'above-mentioned')"
                >Forbidden word: above-mentioned</sch:report>
        </sch:rule>
    </sch:pattern>
</sch:schema>

And suppose you test it with this XSpec:

test1.xspec

<x:description schematron="test.sch" xmlns:x="http://www.jenitennison.com/xslt/xspec">
    <x:scenario focus="test this framework" label="above-mentioned">
        <x:context>
            <conbody>
                <p>above-mentioned</p>
            </conbody>
        </x:context>
        <x:expect-report id="above-mentioned" role="info" />
        <x:expect-report id="above-mentioned" location="//text()[. eq 'above-mentioned']" role="info" />
    </x:scenario>
</x:description>

Both of expect-report tests fail:

C:\test>xspec.bat -s test1.xspec
...
report above-mentioned info
      FAILED
report above-mentioned info //text()[. eq 'above-mentioned']
      FAILED
...
passed: 0 / pending: 0 / failed: 2 / total: 2

They fail, because the skeleton Schematron implementation bundled into XSpec does not visit text nodes by default:

Setting global parameters for Schematron to visit text nodes

To make <sch:rule context="text()"> work, you need to tell the skeleton Schematron implementation to visit text nodes:

test2.xspec

<x:description schematron="test.sch" xmlns:x="http://www.jenitennison.com/xslt/xspec">
    <x:param name="only-child-elements">false</x:param>
    <x:param name="visit-text">true</x:param>

    <x:scenario focus="test this framework" label="above-mentioned">
        <x:context>
            <conbody>
                <p>above-mentioned</p>
            </conbody>
        </x:context>
        <x:expect-report id="above-mentioned" role="info" />
        <x:expect-report id="above-mentioned" location="//text()[. eq 'above-mentioned']" role="info" />
    </x:scenario>
</x:description>

Note that this revised XSpec has two global parameters (/x:description/x:param). They are passed to the Schematron implementation.

This time the skeleton Schematron implementation visits text nodes and the 1st expect-report is now successful:

C:\test>xspec.bat -s test2.xspec
...
report above-mentioned info
report above-mentioned info //text()[. eq 'above-mentioned']
...
ERROR in svrl:successful-report/@location: Expression above-mentioned should point to one node.

*** Error running the test suite

The 2nd expect-report generates a fatal error, because it has @location and the skeleton Schematron implementation cannot handle @location with text nodes. In this case, the skeleton Schematron implementation generates SVRL containing a broken svrl:successful-report/@location.

Using another implementation of Schematron

To make @location work with text nodes, you have to fix the skeleton Schematron implementation privately or use another implementation of Schematron.

Alternatively, use another implementation of Schematron, following instructions in Using SchXslt with XSpec v2.3.2 and earlier.

Also note that SchXslt visits text nodes by default, so you don't need to set global x:param. With SchXslt, you can use test1.xspec instead of test2.xspec for this example.

⚠️ **GitHub.com Fallback** ⚠️