[http://creativecommons.org/licenses/by/3.0/]
This work is licensed under a CC
Attribution 3.0 Unported License [http://creativecommons.org/licenses/by/3.0/]
assert
report
XSD 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>
<grammar xmlns="http://relaxng.org/ns/structure/1.0"> <start><ref name="document"/></start> <define name="document"> <element name="document"> <ref name="heading"/> <ref name="chapter"/> </element> </define> <define name="heading"> <element name="heading"><text/></element> </define> <define name="chapter"> <element name="chapter"> <attribute name="id"><text/></attribute> <ref name="heading"/> <oneOrMore> <element name="para"><text/></element> </oneOrMore> </element> </define> </grammar>
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>
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:sch="http://www.ascc.net/xml/schematron" version="1.0"> <xsl:template match="*|@*" mode="schematron-get-full-path"> <xsl:apply-templates select="parent::*" mode="schematron-get-full-path"/> <xsl:text>/</xsl:text> <xsl:if test="count(. | ../@*) = count(../@*)">@</xsl:if> <xsl:value-of select="name()"/> <xsl:text>[</xsl:text> <xsl:value-of select="1+count(preceding-sibling::*[name()=name(current())])"/> <xsl:text>]</xsl:text> </xsl:template> <xsl:template match="/"> <xsl:apply-templates select="/" mode="M1"/> </xsl:template> <xsl:template match="address" priority="4000" mode="M1"> <xsl:choose> <xsl:when test="(count(phone[@type = 'voice']) > 0) and (count(phone[@type = 'fax']) > 0)"/> <xsl:otherwise>there must be at least one voice and one fax number</xsl:otherwise> </xsl:choose> <xsl:apply-templates mode="M1"/> </xsl:template> <xsl:template match="text()" priority="-1" mode="M1"/> <xsl:template match="text()" priority="-1"/> </xsl:stylesheet>
assert
assert
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(*) )
report
report
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)<schema xmlns="http://www.ascc.net/xml/schematron"> <title>Address Checking</title> <pattern name="Contact Details Checking"> <rule context="address"> <assert test="(count(phone[@type = 'voice']) > 0) and (count(phone[@type = 'fax']) > 0)">ERROR: There must be at least one voice and one fax number</assert> </rule> <rule context="website"> <report test="substring(text(), string-length(text())-3) = '.edu'">REPORT: There is an .edu Web site</report> </rule> </pattern> </schema>