Example code
Consider the following somewhat contrived XML instance:
file.xml
<?xml version="1.0" encoding="UTF-8"?>
<section xmlns:aid="http://ns.adobe.com/AdobeInDesign/4.0/" xmlns:aid5="http://ns.adobe.com/AdobeInDesign/5.0/">
<table aid:trows="3" aid:tcols="2">
<Cell>header column 1</Cell>
<Cell>header column 2</Cell>
<Cell>row 1 column 1</Cell>
<Cell>row 1 column 2</Cell>
<Cell>row 2 column 1</Cell>
<Cell>row 2 column 2</Cell>
</table>
</section>
It successfully validates using the following Relax NG Schema:
schema.rng
<?xml version="1.0" encoding="UTF-8"?>
<grammar xmlns="http://relaxng.org/ns/structure/1.0"
datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"
xmlns:sch="http://purl.oclc.org/dsdl/schematron"
xmlns:aid="http://ns.adobe.com/AdobeInDesign/4.0/"
xmlns:aid5="http://ns.adobe.com/AdobeInDesign/5.0/">
<start>
<ref name="section"/>
</start>
<define name="section">
<element name="section">
<ref name="table"/>
</element>
</define>
<define name="table">
<sch:pattern name="Test attributes aid:rows and aid:tcols when multiplied equal count of Cell elements">
<sch:rule context="table">
<sch:assert test="count(./Cell) = 6">Count of Cell elements does not match specified @aid:rows and @aid:tcols.</sch:assert>
</sch:rule>
</sch:pattern>
<element name="table">
<attribute name="aid:trows">
<data type="integer"/>
</attribute>
<attribute name="aid:tcols">
<data type="integer"/>
</attribute>
<oneOrMore>
<element name="Cell">
<text/>
</element>
</oneOrMore>
</element>
</define>
</grammar>
Note: the embedded Schematron rule in schema.rng
, i.e. the part that reads as follows:
<sch:pattern name="Test attributes aid:rows and aid:tcols when multiplied equal count of Cell elements"> <sch:rule context="table"> <sch:assert test="count(./Cell) = 6">Count of Cell elements does not match specified @aid:rows and @aid:tcols.</sch:assert> </sch:rule> </sch:pattern>
This rule assert
's that the count of Cell
element nodes must equal 6
:
What am I trying to do?
I'm trying to avoid hard coding what the count of Cell
elements must be in the XPath count
function that is currently defined in the Schematron rule. i.e. this part (shown again below) stating that the count of Cell
elements must be six:
<sch:assert test="count(./Cell) = 6">...</sch:assert>
^
What I want to do is infer what the count of Cell
elements must be by multiplying the values of the aid:trows
and aid:tcols
attributes associated with the table
element. i.e. infer it from these attributes in file.xml shown again below:
<table aid:trows="3" aid:tcols="2">
^ ^
...
</table>
What have I tried...
I've tried redefining the XPath count
function in the Schematron rule as follows.
<sch:assert test="count(./Cell) = @aid:trows * @aid:tcols">...</sch:assert>
However, attempting to validate file.xml produces the following error (btw. I'm using Oxygen XML Editor):
Failed to compile stylesheet. 1 error detected. Undeclared namespace prefix {aid} Got a fatal error trying to create a transformer from the stylesheet!
There seems to be some issue with the aid
namespace prefix!
What am I misunderstanding here? How can I fix this?
What does work?
To determine whether it's aid
namespace prefix related I tried the following which does work successfully:
In file.xml I omitted the
aid
prefix from theaid:trows
andaid:tcol
attributes associated with thetable
as shown below:... <table trows="3" tcols="2"> ... </table>
Then redefined:
- the XPath
count
function in the Schematron rule ascount(./Cell) = @trows * @tcols
- and defined the attributes for the
table
astrows
andtcols
, i.e. omitted theaid:
prefixes.
Essentially I redefined the named pattern for
table
to the following:... <define name="table"> <sch:pattern name="Test attributes aid:rows and aid:tcols when multiplied equal count of Cell elements"> <sch:rule context="table"> <!-- change below --> <sch:assert test="count(./Cell) = @trows * @tcols">Count of Cell elements does not match specified @aid:rows and @aid:tcols.</sch:assert> </sch:rule> </sch:pattern> <element name="table"> <!-- change below --> <attribute name="trows"> <data type="integer"/> </attribute> <!-- change below --> <attribute name="tcols"> <data type="integer"/> </attribute> <oneOrMore> <element name="Cell"> <text/> </element> </oneOrMore> </element> </define> ...
- the XPath