|
|
This work is licensed under a Creative Commons |
While XML Schema is the most popular schema language in use today and for the foreseeable future, it is only one representative from a class of languages which are all designed for the purpose of testing whether some XML document satisfies a set of constraints. This test could of course also be conducted programmatically, but this is not portable and not easily maintainable. Schema languages thus often use a declarative approach to specifying how to conduct validation. A very simple yet very powerful language for this is Schematron, which uses the expressive power of XPath for testing whether a document satisfies a set of conditions. Schematron is rule-based in contrast to the more traditional grammar-based schema languages and complements these very well.
& is supported (all is extremely limited)chess = white, (black, white)*, black?content model
<!ELEMENT document (heading, chapter) > <!ELEMENT heading (#PCDATA) > <!ELEMENT chapter (heading, para+) > <!ATTLIST chapter id ID #REQUIRED > <!ELEMENT para (#PCDATA) >
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="document">
<xs:complexType>
<xs:sequence>
<xs:element ref="heading"/>
<xs:element ref="chapter"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="heading" type="xs:string"/>
<xs:element name="chapter">
<xs:complexType>
<xs:sequence>
<xs:element ref="heading"/>
<xs:element name="para" type="xs:string" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="id" type="xs:ID"/>
</xs:complexType>
</xs:element>
</xs:schema>
start = document
document = element document { heading, chapter }
heading = element heading { text }
chapter = element chapter {
attribute id { text },
heading,
element para { text }+
}
validationbefore processing
<schema xmlns="http://www.ascc.net/xml/schematron"> <title>Address Checking</title> <pattern name="Phone Number Checking"> <rule context="address"> <assert test="(count(phone[@type = 'voice']) > 0) and (count(phone[@type = 'fax']) > 0)">there must be at least one voice and one fax number</assert> </rule> </pattern> </schema>
executableand
outputXSLT elements
<xsl:template match="rule"> <xsl:template match="{@context}"> <xsl:apply-templates select="assert"/> </xsl:template> </xsl:template>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:axsl="http://www.w3.org/1999/XSL/TransformAlias" xmlns:sch="http://www.ascc.net/xml/schematron" >
<xsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl"/>
<!-- ASSERT and REPORT -->
<xsl:template match="sch:assert | assert">
<xsl:if test="not(@test)">
<xsl:message>Markup Error: no test attribute in <assert></xsl:message>
</xsl:if>
<axsl:choose>
<axsl:when test="{@test}"/>
<axsl:otherwise>
<xsl:call-template name="process-assert">
<xsl:with-param name="role" select="@role"/>
<xsl:with-param name="id" select="@id"/>
<xsl:with-param name="test" select="normalize-space(@test)" />
<xsl:with-param name="icon" select="@icon"/>
<xsl:with-param name="subject" select="@subject"/>
<xsl:with-param name="diagnostics" select="@diagnostics"/>
</xsl:call-template>
</axsl:otherwise>
</axsl:choose>
</xsl:template>
<xsl:template match="sch:report | report">
<xsl:if test="not(@test)">
<xsl:message>Markup Error: no test attribute in <report></xsl:message>
</xsl:if>
<axsl:if test="{@test}">
<xsl:call-template name="process-report">
<xsl:with-param name="role" select="@role"/>
<xsl:with-param name="test" select="normalize-space(@test)" />
<xsl:with-param name="icon" select="@icon"/>
<xsl:with-param name="id" select="@id"/>
<xsl:with-param name="subject" select="@subject"/>
<xsl:with-param name="diagnostics" select="@diagnostics"/>
</xsl:call-template>
</axsl:if>
</xsl:template>
assertassert is used to specify assertionsfalse, the assertion's content is output<!ELEMENT ENTRY (NAME, ADDRESS, PHONENUM+, EMAIL) >
( count(NAME) = 1 and count(ADDRESS) = 1 and count(EMAIL) = 1 ) and ( NAME[following-sibling::ADDRESS] and ADDRESS[following-sibling::PHONENUM] and PHONENUM[following-sibling::EMAIL] ) and ( count(NAME|ADDRESS|PHONENUM|EMAIL) = count(*) )
reportreport is used to generate reportstrue, then the assertion's content is outputassert and report are inverseassert is used to test conformance (it outputs errors)report id used to report observations (it outputs messages)