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
:
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>
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 the aid:trows
and aid:tcol
attributes associated with the table
as shown below:
...
<table trows="3" tcols="2">
...
</table>
Then redefined:
count
function in the Schematron rule as count(./Cell) = @trows * @tcols
table
as trows
and tcols
, i.e. omitted the aid:
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>
...
Here are some options:
Namespace prefixes used in assert tests in Schemetron must be declared using the Schematron ns
element. Add the following as the first child within <grammar>
in the RelaxNG schema:
<sch:ns prefix="aid" uri="http://ns.adobe.com/AdobeInDesign/4.0/"/>
Alternatively, you can assert the namespace of the attributes within the assert test by using the xPath namespace-uri()
function. Change:
@aid:trows
to:
@*:trows[namespace-uri() = 'http://ns.adobe.com/AdobeInDesign/4.0/']
(and the same for tcols
).
Or, if you're lazy, you can use @*:trows
, which will select trows
attributes of any namespace.