Besides supporting Schematron QuickFix, the Escali offers Schematron extensions which shall make the programming of Schematron schemata more comfortable. The six Escali extension elements and the six extension attributes as well as their functionality shall be introduced in the following. A documentation of the elements can also be found in the Extension reference of Escali Schematron. All extension elements and attributes belong to the http://www.escali.schematron-quickfix.com/ namespace and are provided with the es prefix.
In Schematron, the use of namespaces is unusual and inconvenient. It should be common knowledge that namespaces in Schematron must be declared with <sch:ns> elements. This is an acceptable solution, but the XML developer is not very used to it. However, what can make the developing process very complicated is the fact that in Schematron a default namespace cannot be indicated. Therefore, all XML nodes which belong to a namespace and which shall be checked must be addressed with a prefix.
By using the top-level element <es:default-namespace>, this problem can be avoided with the Escali. For this purpose, the default namespace is indicated in the uri attribute. All elements of the Schematron schema referenced in the XPath expressions without a prefix must belong to this namespace in order to be selected.
1 | <?xml version="1.0" encoding="UTF-8"?> |
2 | <schema xmlns="http://purl.oclc.org/dsdl/schematron" xmlns:es="http://www.escali.schematron-quickfix.com/" queryBinding="xslt2"> |
3 | <es:default-namespace uri="http://www.w3.org/1999/xhtml"/> |
4 | <title>Two different language attributes.</title> |
5 | <pattern> |
6 | <rule context="html"> |
7 | <assert test="@lang">The attribute "lang" is missing.</assert> |
8 | <assert test="@xml:lang">The attribute "xml:lang" is missing.</assert> |
9 | <assert test="@lang = @xml:lang"> The attributes "lang" and "xml:lang" should have the same value.</assert> |
10 | </rule> |
11 | </pattern> |
12 | </schema> |
The <sch:rule> matches the <html> element in the http://www.w3.org/1999/xhtml namespace.
By using the Escali, also the unusual <sch:ns> elements can be avoided. If a prefix used in a XPath expression is not assigned to a namespace with a <sch:ns> element, the Escali does not output an error anymore. The current namespace context according to the XML Recommendation is used to resolve the XPath expression. This procedure is already known from XSLT.
1 | <schema xmlns="http://purl.oclc.org/dsdl/schematron" xmlns:es="http://www.escali.schematron-quickfix.com/" queryBinding="xslt2"> |
2 | <pattern> |
3 | <rule context="*[db:listitem]" xmlns:db="http://docbook.org/ns/docbook"> |
4 | <let name="level" value="count(ancestor::db:listitem)+1"/> |
5 | <report test="$level >= 3">Too many levels in this list. We are in level <value-of select="$level"/>.</report> |
6 | </rule> |
7 | </pattern> |
8 | </schema> |
The XML Recommendation provides that the http://docbook.org/ns/docbook namespace is assigned to the db prefix. This applies within the entire <sch:rule> element, if the prefix in a descendant element is not overwritten with another namespace.
When using the Escali, the namespace context just described also applies for the XPath expressions of the Schematron schema. As a result, the declaration of the namespace with a <sch:ns> element is no longer necessary. Attention: This only applies for prefixes which were not assigned with a <sch:ns> element to a namespace. As a consequence, the <sch:ns> element overwrites all namespace declarations with the same prefix.
The include function of Schematron is rather unsuitable for use in practice. Therefore, many developers switched to work with XInclude in order to make Schematron schemas reusable.
The <sch:include> element includes an entire document per href attribute. This means that the <sch:include> element is replaced by the root element of the referenced document. As a consequence, the referenced document itself must not be a valid Schematron schema. This approach was already extended in the Skeleton of Rick Jelliffe: by indicating an ID, an element can be included within the referenced document. In that case, the href attribute has the following pattern: path/to/schematron/to/import.sch#element-id. Now, the element with the ID (@id) element-id in the import.sch document is included. So, the import.sch document can be a valid Schematron schema.
This method is also implemented in the Escali. However, it has the disadvantage that a <sch:include> element can still only include one pattern. Several patterns or rules (without the enclosing pattern) need one <sch:include> element per pattern/rule.
The Escali now also offers an own Schematron-optimised possibility to reuse a schema in another schema. For this purpose, the top-level element <es:import> is used. In the simplest case, it imports any importable content of another Schematron schema referenced in the href attribute.
Importable content is any top-level element, except for the phases (<sch:phase>) and the title (<sch:title>).
In addition, the <es:import> element offers the possibility to import only certain phases of a Schematron schema. With the phase attribute, only patterns are imported which would be active at one of the indicated phases. Several phases are separated by whitespace.
1 | <?xml version="1.0" encoding="UTF-8"?> |
2 | <schema xmlns="http://purl.oclc.org/dsdl/schematron" xmlns:es="http://www.escali.schematron-quickfix.com/" queryBinding="xslt2" xml:lang="en"> |
3 | <ns uri="http://www.w3.org/1999/xhtml" prefix="html"/> |
4 | <title>Two different language attributes.</title> |
5 | <pattern> |
6 | <rule context="html:html"> |
7 | <assert test="@lang">The attribute "lang" is missing.</assert> |
8 | <assert test="@xml:lang">The attribute "xml:lang" is missing.</assert> |
9 | <assert test="@lang = @xml:lang"> The attributes "lang" and "xml:lang" should have the same value.</assert> |
10 | </rule> |
11 | </pattern> |
12 | <es:import href="escali-ext3-import.sch" phase="diff"/> |
13 | </schema> |
escali-ext3-import.sch:
1 | <?xml version="1.0" encoding="UTF-8"?> |
2 | <schema xmlns="http://purl.oclc.org/dsdl/schematron" queryBinding="xslt2" xml:lang="en"> |
3 | <ns uri="http://www.w3.org/1999/xhtml" prefix="html"/> |
4 | <title>Two different language attributes.</title> |
5 | <phase id="diff"> |
6 | <active pattern="diffP"/> |
7 | </phase> |
8 | <pattern id="diffP"> |
9 | <rule context="*[@xml:lang and @lang]"> |
10 | <assert test="@lang = @xml:lang" diagnostics="langDiff"> The attributes "lang" and "xml:lang" should have the same value.</assert> |
11 | </rule> |
12 | </pattern> |
13 | <pattern id="other"> |
14 | <rule context="*[@lang]"> |
15 | <assert test="@xml:lang" diagnostics="xmlLang">The attribute "xml:lang" is missing.</assert> |
16 | </rule> |
17 | <rule context="*[@xml:lang]"> |
18 | <assert test="@lang" diagnostics="lang">The attribute "lang" is missing.</assert> |
19 | </rule> |
20 | </pattern> |
21 | <diagnostics> |
22 | <diagnostic id="langDiff" xml:lang="de">Die Attribute "lang" und "xml:lang" sollten die selben Werte haben.</diagnostic> |
23 | <diagnostic id="xmlLang" xml:lang="de">Das Attribut "xml:lang" fehlt.</diagnostic> |
24 | <diagnostic id="lang" xml:lang="de">Das Attribut "lang" fehlt</diagnostic> |
25 | </diagnostics> |
26 | </schema> |
The diff phase is imported. Therefore, only the diffP pattern is imported; the other pattern is ignored. However, other elements are always imported, so the <sch:diagnostics> and the <sch:ns> elements. Here, errors will occur if a prefix is assigned to two different namespaces or if IDs are assigned twice.
In practice, a Schematron schema often examines the connections between two XML documents. One of them is usually a configuration file which is fixed stored or referenced in another XML document. However, if the configuration file is variable, this cannot be solved only with Schematron at the moment. The Schematron schema ought to be parametrisable in order to solve this problem.
The Escali knows the top-level element <es:param> whose functionality is identical to the one of the XSLT element <xsl:param>. Permitted are the attributes name, required, select and type.
Here, a somewhat maverick behaviour of Schematron shall be discussed which, in my opinion, makes little sense – but which has already been defended by some people. First off: the Escali does not change the default behaviour of Schematron, it only offers alternatives!
In detail, the behaviour is meant if two rules within a pattern match the same node. This shall be demonstrated by means of an example:
4 | <pattern id="list"> |
5 | <rule context="*[count(listitem) > 10]"> |
6 | <report test="processing-instruction('break')">Long lists should have a mark where the renderer could break the list in two columns.</report> |
7 | </rule> |
8 | <rule context="*[listitem]"> |
9 | <let name="level" value="count(ancestor::listitem)+1"/> |
10 | <report test="$level >= 3">Too many levels in this list. We are in level <value-of select="$level"/>.</report> |
11 | </rule> |
12 | </pattern> |
These two rules shall check on the one hand whether lists with more than 10 items contain a PI with the name break and on the other hand whether a list has more than 3 list levels.
Since these two <sch:rule> elements belong to one pattern, this Schematron schema checks in another way as wished for: Each list with more than ten items is checked for a PI with the name break. The level check is only applied to lists with ten or less items. This happens because in Schematron applies: if there is a node matching two or more rules within a pattern, the node is only checked by means of the first matching rule – irrespective of whether the result of the check is positive or negative.
In practice, this would mean that the following example, if checked against the Schematron schema shown above, will output no error:
8 | <orderedlist> |
9 | <listitem> |
10 | <para>Level 1</para> |
11 | <orderedlist> |
12 | <listitem> |
13 | <para>Level 2</para> |
14 | <orderedlist> |
15 | <listitem> |
16 | <para>Level 3</para> |
17 | <orderedlist> |
18 | <listitem><para>Item 1</para></listitem> |
19 | <listitem><para>Item 2</para></listitem> |
20 | <listitem><para>Item 3</para></listitem> |
21 | <listitem><para>Item 4</para></listitem> |
22 | <listitem><para>Item 5</para></listitem> |
23 | <?break?> |
24 | <listitem><para>Item 6</para></listitem> |
25 | <listitem><para>Item 7</para></listitem> |
26 | <listitem><para>Item 8</para></listitem> |
27 | <listitem><para>Item 9</para></listitem> |
28 | <listitem><para>Item 10</para></listitem> |
29 | <listitem><para>Item 11</para></listitem> |
30 | </orderedlist> |
31 | </listitem> |
32 | </orderedlist> |
33 | </listitem> |
34 | </orderedlist> |
35 | </listitem> |
36 | </orderedlist> |
The highlighted list is in level 4, although only 3 levels are permitted. However, since it contains more than 10 items and a break PI, it does not output an error.
In order that the Schematron schema works as desired, each rule must be nested in an own <sch:pattern> element. In some cases it is not always obvious that two rules could match the same node. Therefore, my advise to Schematron beginners is always the following: "Each pattern only one rule".
But if you think of Schematron schemata with more than 50 <sch:rule> elements and of constructions as phases where each pattern has to be activated separately (for more details see Phases), a large Schematron schema may quickly end in chaos.
In order to arrange several <sch:rule> elements in one pattern, the Escali contains the additional es:matchType attribute with the possible values:
Value |
Description |
---|---|
first |
Normal behaviour of Schematron: Only the first matching <sch:rule> checks the node. |
all |
For each node all matching <sch:rule> elements are taken into account, no matter at which place in the pattern they are located. |
priority |
In this pattern the manually assigned priority of the <sch:rule> elements (for more details see Priority) is taken into account. If a node matches several <sch:rule> elements of this pattern, it will only be checked by means of the <sch:rule> element having highest priority. If several <sch:rule> elements have highest priority, only the first <sch:rule> element will match. |
As shown above, with es:matchType="priority" can be indicated that the manually assigned priority of the <sch:rule> elements shall be taken into account. The manually assigned priority is indicated with the es:priority attribute of the <sch:rule> element. As a value any number of the xs:double type can be indicated. The default value of es:priority is 0.
The priority was implemented mainly for the sake of completeness. Furthermore, it offers the possibility to make the problem of the double rule matching described above clear to the Schematron developer or other co-developers. For example, the errors described above often occur in case an existing Schematron schema is supplemented by further rules.
However, the greatest benefits for the es:matchType attribute brings the all value. In this way, <sch:rule> elements can be grouped within patterns without having to fear that a <sch:rule> element does not match under certain circumstances the way it should. So, the example with the lists can easily be extended so that also lists with more than 10 items in the level 4+ produce an error:
4 | <pattern id="list" es:matchType="all"> |
5 | <rule context="*[count(listitem) > 10]"> |
6 | <report test="processing-instruction('break')">Long lists should have a mark where the renderer could break the list in two columns.</report> |
7 | </rule> |
8 | <rule context="*[listitem]"> |
9 | <let name="level" value="count(ancestor::listitem)+1"/> |
10 | <report test="$level >= 3">Too many levels in this list. We are in level <value-of select="$level"/>.</report> |
11 | </rule> |
12 | </pattern> |
As already indicated in the previous section, the use of phases in big Schematron schemas with a large number of patterns can become confusing or end in chaos. In Schematron, for a phase (<sch:phase>) it is only possible to activate individual patterns. All other patterns are automatically inactive when using this phase. But if individual patterns are added to an existing schema, they must be updated in each phase which shall use these patterns. Even worse: if a new phase is added, all patterns which shall be used must be listed there individually. Statements as "all patterns except for ..." cannot be made!
For this purpose, in the Escali two additional elements and one additional attribute were implemented.
By using the <es:phase> element, reference can be made to another phase within a <sch:phase> element. All patterns which are activated or deactivated in the referenced phase are also activated or deactivated in the referencing phase.
Since no large Schematron schemata can be introduced here, an abstract example must meet our requirements:
1 | <?xml version="1.0" encoding="UTF-8"?> |
2 | <schema xmlns="http://purl.oclc.org/dsdl/schematron" xmlns:db="http://docbook.org/ns/docbook" xmlns:es="http://www.escali.schematron-quickfix.com/" queryBinding="xslt2"> |
3 | <phase id="phaseA"> |
4 | <active pattern="patternA"/> |
5 | </phase> |
6 | <phase id="phaseB"> |
7 | <es:phase ref="phaseA"/> |
8 | <active pattern="patternB"/> |
9 | </phase> |
10 | <pattern id="patternA"> |
11 | <title>A</title> |
[...] | |
15 | </pattern> |
16 | <pattern id="patternB"> |
17 | <title>B</title> |
[...] | |
21 | </pattern> |
22 | <pattern id="patternC"> |
23 | <title>C</title> |
[...] | |
27 | </pattern> |
28 | </schema> |
The example contains the three patterns A, B and C, the two phases phaseA and phaseB as well as the build-in phase #ALL. The behaviour of the phases phaseA and #ALL is already known from Schematron.
Now, the phaseB phase references the phaseA phase. This is carried out via the ref attribute of the <es:phase> element. Here, the ID of the phaseA phase is indicated. In the phaseB phase, not only the pattern B but also the pattern A is active.
With the deactivation of patterns, it shall be possible that statements as "all patterns except for ..." can be implemented. For this purpose, the Escali knows the <es:inactive> element. This element works exactly like the <sch:active> element with a reference to a pattern in the pattern attribute, just with the reverse effect: the referenced pattern is explicitly deactivated. However, this can only make sense if, in addition, the following rule applies: if a <sch:phase> element contains or references only <es:inactive> elements, all patterns not deactivated will be active.
If a <sch:phase> element contains <sch:active> as well as <es:inactive> elements, only patterns will be active which were activated by a <sch:active> element but not deactivated by an <es:inactive> element. An example now follows in which constellation such a use would make sense.
1 | <?xml version="1.0" encoding="UTF-8"?> |
2 | <schema xmlns="http://purl.oclc.org/dsdl/schematron" xmlns:db="http://docbook.org/ns/docbook" xmlns:es="http://www.escali.schematron-quickfix.com/" queryBinding="xslt2"> |
3 | <phase id="phaseA"> |
4 | <active pattern="patternA"/> |
5 | <active pattern="patternB"/> |
6 | <active pattern="patternC"/> |
7 | </phase> |
8 | <phase id="phaseB"> |
9 | <es:phase ref="phaseA"/> |
10 | <es:inactive pattern="patternB"/> |
11 | </phase> |
12 | <phase id="phaseC"> |
13 | <es:inactive pattern="patternB"/> |
14 | </phase> |
15 | <pattern id="patternA"> |
16 | <title>A</title> |
[...] | |
20 | </pattern> |
21 | <pattern id="patternB"> |
22 | <title>B</title> |
[...] | |
26 | </pattern> |
27 | <pattern id="patternC"> |
28 | <title>C</title> |
[...] | |
32 | </pattern> |
33 | <pattern id="patternD"> |
34 | <title>D</title> |
[...] | |
38 | </pattern> |
39 | </schema> |
The phaseC phase only contains one <es:inactive> element. Therefore, only the patterns A, C and D (all except for pattern B) are active.
The phaseB phase combines the Escali extensions <es:inactive> and <es:phase>. Here, the <sch:active> elements of the referenced phaseA phase are adopted, however, the pattern B activated in this way is again deactivated by the <es:inactive> element. Only the patterns A and C remain active.
This example could also be rewritten by reusing the phaseC phase for the phaseB phase:
3 | <phase id="phaseA"> |
4 | <active pattern="patternA"/> |
5 | <active pattern="patternB"/> |
6 | <active pattern="patternC"/> |
7 | </phase> |
8 | <phase id="phaseB"> |
9 | <es:phase ref="phaseA"/> |
10 | <es:phase ref="phaseC"/> |
11 | </phase> |
12 | <phase id="phaseC"> |
13 | <es:inactive pattern="patternB"/> |
14 | </phase> |
In this example, the phaseB phase would have the same effect: patterns A and C would be active.
Assuming that patterns shall be written belonging to the core of the Schematron schema. They shall not be re-activated in each phase because without them the schema does not make sense anymore. On the basis of this assumption, the es:active attribute was developed for the Escali. This attribute determines for each pattern a default status, which means whether it shall be active (true) or inactive (false) per default or whether this is left to the phase (auto).
The principle is as follows: Only <sch:active> or <es:inactive> elements overwrite the default status of the pattern. As a consequence, a pattern with es:active="true" is only inactive if it was deactivated by a <es:inactive> element. Here it does not matter whether the phase only contains <sch:active> or <es:inactive> elements.
The same rule applies for patterns with es:active="false", only in reverse form: This pattern will only be active if it is activated by a <sch:active> element.
1 | <?xml version="1.0" encoding="UTF-8"?> |
2 | <schema xmlns="http://purl.oclc.org/dsdl/schematron" xmlns:db="http://docbook.org/ns/docbook" xmlns:es="http://www.escali.schematron-quickfix.com/" queryBinding="xslt2"> |
3 | <phase id="phaseA"> |
4 | <active pattern="patternA"/> |
5 | </phase> |
6 | <phase id="phaseB"> |
7 | <es:inactive pattern="patternB"/> |
8 | </phase> |
9 | <phase id="phaseC"> |
10 | <active pattern="patternC"/> |
11 | </phase> |
12 | <phase id="phaseD"> |
13 | <es:inactive pattern="patternD"/> |
14 | </phase> |
15 | <pattern id="patternA"> |
16 | <title>A</title> |
[...] | |
20 | </pattern> |
21 | <pattern id="patternB" es:active="auto"> |
22 | <title>B</title> |
[...] | |
26 | </pattern> |
27 | <pattern id="patternC" es:active="false"> |
28 | <title>C</title> |
[...] | |
32 | </pattern> |
33 | <pattern id="patternD" es:active="true"> |
34 | <title>D</title> |
[...] | |
38 | </pattern> |
39 | </schema> |
Phase ID |
Active patterns |
Description |
---|---|---|
phaseA |
A and D |
Pattern A is active and activated per <sch:active> element. Pattern B is inactive because the phase only contains a <sch:active> element. Pattern C is inactive because it is inactive per default and not activated per <sch:active> element. Pattern D is active because it is active per default and not deactivated per <es:inactive> element. |
phaseB |
A and D |
Pattern A is active because the phase only contains an <es:inactive> element. Pattern B is inactive and deactivated per <es:inactive> element. Pattern C is inactive because it is inactive per default and not activated per <sch:active> element. Pattern D is active because it is active per default and not deactivated per <es:inactive> element. |
phaseC |
C and D |
Pattern A is inactive because the phase only contains a <sch:active> element. Pattern B is inactive because the phase only contains a <sch:active> element. Pattern C is active and activated per <sch:active> element. Pattern D is active because it is active per default and not deactivated per <es:inactive> element. |
phaseD |
A and B |
Pattern A is active because the phase only contains a <es:inactive> element. Pattern B is active because the phase only contains a <es:inactive> element. Pattern C is inactive because it is inactive per default and not activated per <sch:active> element. Pattern D is inactive and deactivated per <sch:inactive> element. |
The localisation options are derived from the Schematron Standard (ISO/IEC 19757-3). In Annex G, an example for a multi-lingual Schematron schema is shown. Each <sch:report> or <sch:assert> element references to several <sch:diagnostic> elements having different languages (@xml:lang):
1 | <sch:schema xmlns:sch="http://purl.oclc.org/dsdl/schematron" xml:lang="en"> |
2 | <sch:title>Example of a Multi-Lingual Schema</sch:title> |
3 | <sch:pattern> |
4 | <sch:rule context="dog"> |
5 | <sch:assert test="bone" diagnostics="d1 d2"> |
6 | A dog should have a bone. |
7 | </sch:assert> |
8 | </sch:rule> |
9 | </sch:pattern> |
10 | <sch:diagnostics> |
11 | <sch:diagnostic id="d1" xml:lang="en"> |
12 | A dog should have a bone. |
13 | </sch:diagnostic> |
14 | <sch:diagnostic id="d2" xml:lang="de"> |
15 | Ein Hund sollte einen Knochen haben. |
16 | </sch:diagnostic> |
17 | </sch:diagnostics> |
18 | </sch:schema> |
This notation is supported by the Escali in extended form:
The $es:lang parameter is used for indicating in which language the user wants to have displayed the Schematron schema. The value of the parameter is the appropriate language code or the values #ALL or #DEFAULT:
Value |
Description |
---|---|
#DEFAULT |
If the <sch:schema> element contains a xml:lang attribute, the language code indicated here is used. Otherwise the value #ALL applies. This value is also the default value of the parameter. |
#ALL |
The xml:lang attributes are ignored. All languages are outputted, as it is provided for in the Schematron Standard. |
Language codes |
The Escali only adopts human-readable text belonging to the appropriate language. For this purpose, the xml:lang attributes in the Schematron schema are evaluated according to the XML Recommendation. Human-readable text:
|
The selection of the appropriate language may lead to the result that a <sch:assert> or a <sch:report> element does no longer contain its own error message, but only a reference to <sch:diagnostic> elements.
In the example from the Schematron Standard this will be the case if during the validation with the Escali the language code de is passed on to the $es:lang parameter. If there is, as in the present case, only one referenced <sch:diagnostic> element in this language, the Escali converts the <sch:diagnostic> element into the error message for the <sch:report>/<sch:assert> element. In this way, localised SVRL error reports can be generated without always having to indicate all languages.
One reason why Schematron is so powerful is, that it is based on XPath and XSLT. But this leads also to some limitations. One is, that it is only possible to check on a node level. Each Schematron error location needs to be a whole node. But in documents, there are often just single text phrases the cause of the error. If you multiple such incorrect text phrases in the same text node and from the same kind of Schematron error, you will only have one error for this text node.
The best way to demonstrate this issue is, a spell checking Schematron schema. Let us assume, we want to check for the correct spell of the word QuickFix:
1 | <sch:schema xmlns:sch="http://purl.oclc.org/dsdl/schematron" xml:lang="en" queryBinding="xslt2"> |
2 | <sch:title>Example for text phrase errors</sch:title> |
3 | <sch:pattern> |
4 | <sch:rule context="text()"> |
5 | <sch:report test="matches(., 'quick-fix|quick\sfix', 'i')">Please use "QuickFix".</sch:report> |
6 | </sch:rule> |
7 | </sch:pattern> |
8 | </sch:schema> |
This works very well, but in a long paragraph with multiple usages of the term QuickFix, it is hard to find the misspelled one or two:
1 | <?xml version="1.0" encoding="UTF-8"?> |
[...] | |
3 | <?xml-model href="escali-ext7.sch" type="application/xml" schematypens="http://purl.oclc.org/dsdl/schematron"?> |
4 | <section> |
5 | <title>What is the idea?</title> |
6 | <p>In order to save money and nerves we will give the author the chance to solve the problem by himself without producing new errors. The Schematron report should not only list what the author did wrong. It should give him options – called Quick Fixes – to fix these errors. The author can now choose which QuickFix is the right fix for the corresponding Schematron error.</p> |
7 | <p>When he has chosen the matching Quick Fixes, he can "execute" them. With one click his problems end in smoke. Of course, we do not want to pretend that it is that easy. For many errors, no perfect Quick-Fix exists. However, sometimes the errors have to be fixed manually. But the Quick-fixes can help in many situations.</p> |
8 | </section> |
In the two paragraphs above the term QuickFix was misspelled four times, but we only two errors – one for each paragraph. And inside of the paragraph the user have to find them by them self. The Escali provides an extension to set the context not only on nodes but also on text phrases. The text phrases will be identified by regular expressions. To use this extension the <sch:rule> element should have an es:regex attribute. If a regex flag is needed, the es:regexFlags should be added too.
1 | <sch:schema xmlns:sch="http://purl.oclc.org/dsdl/schematron" xmlns:es="http://www.escali.schematron-quickfix.com/" xml:lang="en" queryBinding="xslt2"> |
2 | <sch:title>Example for text phrase errors</sch:title> |
3 | <sch:pattern> |
4 | <sch:rule context="text()" es:regex="quick-fix|quick\sfix" es:regexFlags="i"> |
5 | <sch:report test="true()">Please use "QuickFix".</sch:report> |
6 | </sch:rule> |
7 | </sch:pattern> |
8 | </sch:schema> |
Now the result should be four errors for each misspelled term. The Schematron error location should be displayed only on the position of the text phrases, which matches to the regular expression in es:regex.
This extension has some consequences and requirements to respect:
Context: the context inside of the rule is an string - similar to the usage age of the XSLT instruction <xsl:analyze-string>.
To achieve the context of the current matching node (context), there is a build-in variable $es:current. It returns the current context node which was analyzed by the regular expression.
QuickFixes: there is not a finished solution for combining this extension with QuickFixes. Theoretically all activity elements which match to the current context (@match="." or no match attribute) should replace or delete only the text phrase which is the context of the current error. But there is no implementation for it until now, because it is quite tricky.
No elements: A requirement for the usage of this extension is, that the context attribute of the <sch:rule> needs to match on nodes which are not elements. Elements could contain mixed content, which leads to much problems for implementing this extension.
Schematron has the wonderful option to define beside errors also warnings and informations using the role attribute. But warnings and additional informations could be very destructive if they pop up multiple cases, in which they should be ignored. This is why a ignore function is sometimes very useful. Of course a it is possible to build up a ignore function by the Schematron developer him self. But this leads to much work. The Escali provides a build-in extension for this issue to save work for the developer.
With the es:ignorableId attribute you are able to mark <sch:report> or <sch:assert> elements as ignorable. The value should be an unique ignore-id, so it is possible to refer to this Schematron test:
1 | <sch:schema xmlns:sch="http://purl.oclc.org/dsdl/schematron" xmlns:es="http://www.escali.schematron-quickfix.com/" xml:lang="en" queryBinding="xslt2"> |
2 | <sch:title>Example for text phrase errors</sch:title> |
3 | <sch:pattern> |
4 | <sch:rule context="text()"> |
5 | <sch:report test="matches(., 'quick-fix|quick\sfix', 'i')" es:ignorableId="quickFixSpell">Please use "QuickFix".</sch:report> |
6 | </sch:rule> |
7 | </sch:pattern> |
8 | </sch:schema> |
The extension is based on the convention, which says, that each node will be ignored for this check, if it
has as first preceding sibling a es_ignore-PI.
The value of the PI should be an whitespace separated list of IDs. One id should be the corresponding ignore-id.
If a <sch:assert> or <sch:report> element has an es:ignorableId attribute, the Escali provides automatically QuickFixes to create such a PI to ignore the error.
© Copyright 2014-2018 Nico Kutscherauer (last update 2018-07-17)
Imprint – Privacy Policy – Contact – Sitemap