DTD | XML Schema | Relax NG | Schematron

This page contains examples of validating XML documents using DTD, XML Schema, Relax NG and Schematron

Cardinality

  • ?: optional
  • +: one or more
  • *: zero or more
  • ,: ordered sequence
  • |: choice
  • &: unordered sequence

DTD

W3C Recommendation

http://www.w3.org/TR/REC-xml#dt-doctype

Validation

Validome: http://www.validome.org/grammar/

Attribute datatypes

  • CDATA
  • IDREF
  • IDREFS
  • ENTITY
  • ENTITIES
  • MNTOKEN
  • NMTOKENS
  • NOTATION

Attribute Keywords

  • #REQUIRED
  • #IMPLIED
  • #FIXED 'VALUE'

Organisation

<!ELEMENT organisation (dataprovidername, description, administrators, address, website?)>
<!ATTLIST organisation organisationkey CDATA #REQUIRED>
                       logo ENTITY #IMPLIED>
<!ELEMENT dataprovidername (#PCDATA)>
<!ATTLIST dataprovidername abbreviation CDATA #IMPLIED>                  
<!ELEMENT description (#PCDATA)>
<!ELEMENT administrators (admin: administrator)+>
<!ELEMENT administrator (admin:name, admin:email, admin:telephone)>
<!ATTLIST administrator userkey ID #REQUIRED>
<!ELEMENT address (#PCDATA)>
<!ATTLIST address postcode CDATA #REQUIRED>
<!ELEMENT website (#PCDATA)>
<!-- Notation Declaration -->
<!NOTATION png SYSTEM "firefox.exe">
<!ENTITY logo SYSTEM "http://data.nbn.org.uk/logo.png" NDATA png>

NBN Exchange

<!ELEMENT dataset (administrators, publicaccess, metadata, records)>
<!-- Parameter Entity -->
<!ENTITY % accesscontentmodel "(resolution, download, attributes?, sensitive?, recorder?, validation)">
<!ELEMENT administrators (administrator)+>
<!ELEMENT aadministrator (name, email)>
<!ATTLIST administrator userkey ID #REQUIRED>
<!ELEMENT name (#PCDATA)>
<!ELEMENT email (#PCDATA)>
<!ELEMENT publicaccess %accesscontentmodel;>
<!ELEMENT resolution (#PCDATA)>
<!ELEMENT download (#PCDATA)>
<!ELEMENT attributes (#PCDATA)>
<!ELEMENT sensitive (#PCDATA)>
<!ELEMENT recorder (#PCDATA)>
<!ELEMENT validation EMPTY>
<!ELEMENT metadata (title, description, methods, purpose, geographic, temporal, quality, additionalinformation, accessconstraints, useconstraints)>
<!ELEMENT title (#PCDATA |i)>
<!ELEMENT description (#PCDATA|i)>
<!ELEMENT methods (#PCDATA)>
<!ELEMENT purpose (#PCDATA)>
<!ELEMENT geographic (#PCDATA)>
<!ELEMENT temporal (#PCDATA)>
<!ELEMENT quality (#PCDATA)>
<!ELEMENT additionalinformation (#PCDATA)>
<!ELEMENT accessconstraints (#PCDATA)>
<!ELEMENT useconstraints (#PCDATA)>
<!ELEMENT records (record)+>
<!ELEMENT record (surveykey?, samplekey?, (vaguedate | date), (taxonversionkey | biotopekey), zeroabundance?, sensitive?, sitename?, spatialreference, recorder?, determiner?, attributes?)>
<!ATTLIST record recordkey ID #REQUIRED>
<!ELEMENT surveykey (#PCDATA)>
<!ELEMENT samplekey (#PCDATA)>
<!ELEMENT vaguedate (startdate, enddate, datetype)>
<!ELEMENT startdate (#PCDATA)>
<!ELEMENT enddate (#PCDATA)>
<!ELEMENT datetype (#PCDATA)>
<!ELEMENT date (#PCDATA)>
<!ELEMENT taxonversionkey (#PCDATA)>
<!ELEMENT biotopekey (#PCDATA)>
<!ELEMENT zeroabundance (#PCDATA)>
<!ELEMENT sensitive (#PCDATA)>
<!ELEMENT sitename (#PCDATA)>
<!ATTLIST sitename sitekey ID #IMPLIED>
<!ELEMENT spatialreference (gridreference | (east, north)>
<!ATTLIST spatialreference precision NMTOKEN #REQUIRED>
<!ATTLIST spatialreference projection (OSGB | OSNI | OSI | WGS84 | OSGB36) "OSGB" #REQUIRED>
<!ELEMENT gridreference (#PCDATA)>
<!ELEMENT north (#PCDATA)>
<!ELEMENT east (#PCDATA)>
<!ELEMENT recorder (#PCDATA)>
<!ELEMENT determiner (#PCDATA)>
<!ELEMENT attributes (attribute*)?>
<!ELEMENT attribute (#PCDATA)>
<!ATTLIST attribute fieldname NMTOKEN #REQUIRED>
<!-- General Entities -->
<!ENTITY EntityValue EntityTranlsatedValue
<!ENTITY accessconstraintextentity SYSTEM|PUBLIC '-//nbntrust//accessconstraint//EN' 'accessconstraint.txt'>
<!ENTITY useconstraintentity "The Gateway Terms and Conditions are applied to all datasets on the Gateway as a default">

Additional DTD

<!ELEMENT elementname ANY>

XML Schema

W3C Recommendation

DataTypes

string
  normalizedString
    Token
     Language
     NMTOKEN
     NMTOKENS
     Name
      NCName
        ID
        IDREF
        IDREFS
        ENTITY
        ENTITIES
Boolean: true|false|1|0
decimal
  integer
    NonPositiveInteger (<=0)
    NegativeInteger (<0)
    Long (+-92233720368547758080)
      Int (+-2147483648)
        short (+-32768)
          byte (+-128)
    nonNegativeInteger (>=0)
     unsignedLong (18446744073709551615)
       unsignedInt (4294967295)
         unsignedShort (65535)
           unsignedByte (255)
     positiveInteger (>0)  
float
double
duration: PnYnMnDTnHnMnS
dateTime: YYYY-MM-DDThh:mm:ss
time: hh:mm:ss.sss
date: YYYY-MM-DD
gYearMonth: YYYY-MM
gYear: YYYY
gMonthDay: --MM-DD
gDay: ---DD
gMonth: --MM
hexBinary
base64Binary
anyURI
QName
NOTATION

Organisation

<?xml version='1.0' encoding='UTF-8'?>
<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'
    targetNamespace='http://data.nbn.org.uk/organisation'
    xmlns='http://data.nbn.org.uk/organisation'
    elementFormDefault='qualified'
    attributeFormDefault='unqualified'
    version='1.0'
    xml:lang='en-GB'>
<!-- ANONYMOUS COMPLEX TYPE -->
  <xs:element name='organisation'>
      <xs:annotation>
        <xs:appinfo source='http://data.nbn.org.uk/organisation'/>
        <xs:documentation>Organisation details</xs:documentation>
      </xs:annotation>
      <xs:complexType>
     <xs:sequence>
 <!-- ANONYMOUS COMPLEX TYPE -->    
         <xs:element name='dataprovidername'>
                <xs:complexType>
                  <xs:simpleContent>
                    <xs:extension base='xs:string'>
                     <xs:attribute name='abbreviation' type='xs:token' use='optional'/>
                    </xs:extension>
                  </xs:simpleContent>
                </xs:complexType>
             </xs:element>
<!-- ATOMIC SIMPLE TYPE -->
             <xs:element name='description' type='xs:string'/>
 <!-- ANONYMOUS COMPLEX TYPE -->    
             <xs:element name='administrators'>
                <xs:complexType>
                   <xs:element name='administrator' maxOccurs='unbound'/>
                      <xs:complexType>
                         <xs:sequence>
                            <xs:element name='name' type='xs:string'/>
                            <xs:element name='email' type='xs:token'/>
                            <xs:element name='telephone' type='xs:positiveinteger' nillable='true' />
                       </xs:sequence>
                       <xs:attribute name='userkey' type='xs:token' use='required'/>
                    </xs:complexType>
                   </xs:element>
                </xs:complexType>
             </xs:complexType>
 <!-- ANONYMOUS COMPLEX TYPE -->    
             <xs:element name='address'>
              <xs:complexType>
               <xs:simpleContent>
                    <xs:extension base='xs:string'>
                      <xs:attribute name='postcode' type='xs:string' use='required'/>
                    </xs:extension>
                  </xs:simpleContent>
                </xs:complexType>
             </xs:element>
<!-- ATOMIC SIMPLE TYPE -->
             <xs:element name='website' type='xs:string' minoccurs='0'/>
         </xs:sequence>
         <xs:attribute name='organisationkey' type='xs:token' use='required'/>
         <xs:attribute name='logo' type='xs:token' use='optional'/>
      </xs:complexType>
    </xs:element>
</xs:schema>

Administrators

<?xml version='1.0' encoding='UTF-8'?>
<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'
    targetNamespace='http://data.nbn.org.uk/admin'
    xmlns='http://data.nbn.org.uk/admin'
    elementFormDefault='qualified'
    attributeFormDefault='unqualified'
    version='1.0'
    xml:lang='en-GB'>
  <xs:element name='administrators'>
    <xs:annotation>
       <xs:documentation>Administrator details</xs:documentation>
    </xs:annotation>
    <xs:complexType>
       <xs:element name='administrator' type='xs:adminGroup' maxOccurs='unbound'/>
    </xs:complexType>
  </xs:element>
<-- NAMED COMPLEX TYPE -->
  <xs:complexType name='adminGroup'>
    <xs:sequence>
      <xs:element name='name' type='xs:string'/>
      <xs:element name='email' type='xs:token'/>
    </xs:sequence>
    <xs:attribute name='userkey' type='xs:token' use='required'/>
  </xs:complexType>
</xs:schema>

Public Access

<?xml version='1.0' encoding='UTF-8'?>
<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'
    targetNamespace='http://data.nbn.org.uk/access
    xmlns='http://data.nbn.org.uk/access
    elementFormDefault='qualified'
    attributeFormDefault='unqualified'
    version='1.0'
    xml:lang='en-GB'>
 <!-- ANONYMOUS COMPLEX TYPE -->    
  <xs:element name='publicaccess'>
    <xs:annotation>
        <xs:documentation>Public Access details</xs:documentation>
     </xs:annotation>
    <xs:complexType>
      <xs:sequence>
       <xs:element name='resolution' type='resolutiontype' />
       <xs:element name='download' type='xs:boolean'/>
       <xs:element name='attributes' type='xs:boolean'/>
       <xs:element name='sensitive' type='xs:boolean' fixed='false'/>
       <xs:element name='recorder' type='xs:boolean'/>
       <xs:element name='validation' type='xs:boolean' fixed='false'/>
      </xs:sequence>
     </xs:complexType>
  </xs:element>
<!-- USER DEFINED DATATYPE WITH ENUMERATION -->
        <xs:simpleType name='resolutiontype'>
         <xs:restriction base='xs:token'>
           <xs:enumeration value='Full'/>
           <xs:enumeration value='10km'/>
           <xs:enumeration value='2km'/>
           <xs:enumeration value='1km'/>
           <xs:enumeration value='None'/>
         </xs:restriction>
        </xs:simpleType>
</xs:schema>

Metadata

<?xml version='1.0' encoding='UTF-8'?>
<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'
    targetNamespace='http://data.nbn.org.uk/metadata'
    xmlns='http://data.nbn.org.uk/metadata'
    elementFormDefault='qualified'
    attributeFormDefault='unqualified'
    version='1.0'
    xml:lang='en-GB'>
<!-- ANONYMOUS COMPLEX TYPE -->    
  <xs:element name='metadata'>
    <xs:complexType>
      <xs:sequence>
        <xs:element name='title' type='xs:string'/>
        <xs:element name='description' type='xs:string'/>
        <xs:element name='methods' type='xs:string'/>
        <xs:element name='purpose' type='xs:string'/>
        <xs:element name='geographic' type='xs:string'/>
        <xs:element name='temporal' type='xs:string'/>
        <xs:element name='quality' type='xs:string'/>
        <xs:element name='additionalinformation' type='xs:string' minOccurs='0' />
        <xs:element name='accessconstraint' type='xs:string' default='None applied' />
        <xs:element name='useconstraint' type='xs:string' default='The Gateway Terms and Conditions apply' />
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

NBN Exchange

<?xml version='1.0' encoding='UTF-8'?>
<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'
    targetNamespace='http://data.nbn.org.uk/dataset'
    xmlns='http://data.nbn.org.uk/dataset'
    xmlns:admin='http://data.nbn.org.uk/admin'
    xmlns:access='http://data.nbn.org.uk/access'
    xmlns:meta='http://data.nbn.org.uk/metadata'
    elementFormDefault='qualified'
    attributeFormDefault='unqualified'
    version='1.0'
    xml:lang='en-GB'>
<-- IMPORT EXTERNAL XML SCHEMA WITH DIFFERING NAMESPACE-->
  <xs:import namespace='http://data.nbn.org.uk/admin'
          schemaLocation='http://data.nbn.org.uk/admin' 'admin.xsd'/>
  <xs:import namespace='http://data.nbn.org.uk/access'
          schemaLocation='http://data.nbn.org.uk/admin' 'access.xsd'/>
  <xs:import namespace='http://data.nbn.org.uk/access'
          schemaLocation='http://data.nbn.org.uk/metadata' 'metadata.xsd'/>
<-- INCLUDE EXTERNAL XML SCHEMA WITH SAME NAMESPACE -->
  <xs:include schemaLocation='http://data.nbn.org.uk/datatyperestrictions' />
<!-- ANONYMOUS COMPLEX TYPE -->    
  <xs:element name='nbnexchange'>
      <xs:annotation>
        <xs:appinfo source='http://data.nbn.org.uk/nbnexchangeformat'/>
        <xs:documentation>NBN Exchange Format</xs:documentation>
      </xs:annotation
     <xs:complexType>
         <xs:element name='dataset'>
           <xs:complexType>
             <xs:sequence>
               <xs:element ref='admin:administrators'/>
               <xs:element ref='access:publicaccess'/>
               <xs:element ref=meta:metadata'/>
               <xs:element name='records'>
                 <xs:complexType>
                    <xs:element name= 'record' maxOccurs='unbound'>
                      <xs:complexType>
                        <xs:all>
                          <xs:element name='surveykey' type='xs:tokenkey' minOccurs='0' />
                          <xs:element name='samplekey' type='xs:extendedtokenkey' minOccurs='0' />
<!-- CHOICE AND GROUP -->
                          <xs:choice>
                            <xs:element name='vaguedate'>
                              <xs:complexType>
                                <xs:group ref='vaguedategroup'/>
                              </xs:complexType>
                            </xs:element>
                            <xs:element name='date' type='xs:date' />
                          </xs:choice>
                          <xs:choice>
                            <xs:element name='taxonversionkey' type='xs:speciesdictionarykey' />
                            <xs:element name='biotopekey' type='xs:speciesdictionarykey' />
                          </xs:choice>
                          <xs:element name='zeroabudance' type='xs:booleantype' minOccurs='0' />
                          <xs:element name='sensitive' type='xs:booleantype' default='F'/>
                          <xs:element name='sitename'>
                            <xs:complexType>
                              <xs:simpleContent>
                                <xs:extension base='xs:string'>
                                  <xs:attribute name='sitekey'>
                                    <xs:simpleType>
                                      <xs:union memberTypes='xs:positiveInteger' 'xs:tokenKey' />
                                    </xs:simpleType>
                                  </xs:attribute>
                                </xs:extension>
                               </xs:simpleContent>
                             </xs:complexType>
                           </xs:element>
                           <xs:element name='spatialreference'>
                             <xs:complexType>
                               <xs:choice>
                                <xs:element name='gridreference'>
                                  <xs:complexType>
                                    <xs:simpleContent>
                                      <xs:extension base='token'>
                                        <xs:attributeGroup ref='spatialreference' use='required'/>
                                      </xs:extension>
                                    </xs:simpleContent>
                                   </xs:complexType>
                                  </xs:element>
                                 <xs:element type='datum'/>
                               </xs:choice>
                              </xs:complexType>
                            </xs:element>
                            <xs:element name='recorder' type='xs:string' minOccurs='0' />
                            <xs:element name=determiner' type='xs:string' minOccurs='0' />
                            <xs:element name='attributes' minOccurs='0'>
                              <xs:complexType>
                                <xs:element name=attribute type='xs:text' maxOccurs='unbound' />
                              </xs:complexType>
                            </xs:element>
                          </xs:all>
                          <xs:attribute name='recordkey' use='required'>
                            <xs:simpleType>
                              <xs:union memberTypes='xs:positiveInteger' 'xs:tokenKey' />
                            </xs:simpleType>
                          </xs:attribute>
                      </xs:complexType>
                    </xs:element>
                 </xs:complexType>
               </xs:element>
             </xs:sequence>
             <xs:attribute name='datasetkey' type='xs:token' use='required'/>
           </xs:complexType> 
     </xs:complexType> 
   </xs:element>
</xs:schema>

User defined data types

<?xml version='1.0' encoding='UTF-8'?>
<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'
    targetNamespace='http://data.nbn.org.uk/dataset'
    xmlns='http://data.nbn.org.uk/dataset'
    elementFormDefault='qualified'
    attributeFormDefault='unqualified'
    version='1.0'
    xml:lang='en-GB'>
<!-- GROUP -->
  <xs:group name='vaguedategroup'>
   <xs:all>
        <xs:element name='startdate' type='xs:date' use='optional'/>
        <xs:element name='enddate' type='xs:date' />
<!-- USER DEFINED DATATYPE WITH ENUMERATION -->
        <xs:element name='datetype' >
           <xs:simpleType>
             <xs:restriction base='xs:token'>
               <xs:enumeration value='D'/>
               <xs:enumeration value='DD'/>
               <xs:enumeration value='O'/>
               <xs:enumeration value='OO'/>
               <xs:enumeration value='Y'/>
               <xs:enumeration value='YY'/>
               <xs:enumeration value='-Y'/>
               <xs:enumeration value='ND'/>
               <xs:enumeration value='U'/>
               <xs:enumeration value='P'/>
             </xs:restriction>
           </xs:simpleType>
         </xs:element>
   </xs:all>
  </xs:group> 
<!-- RESTRICTION TYPES -->
   <xs:simpleType name='speciesdictionarykey'>
     <xs:restriction base='token'>
       <xs:maxLength='16' />
     </xs:restriction>
   </xs:simpleType>
    <xs:simpleType name='booleantype'>
     <xs:restriction base='xs:token'>
       <xs:enumeration value='T'/>
       <xs:enumeration value='F'/>
     </xs:restriction>
    </xs:simpleType>
     <xs:simpleType name='tokenkey'>
       <xs:restriction base='xs:token'>
         <xs:minLength='1'/>
         <xs:maxLength='30'/>
       </xs:restriction>
     </xs:simpleType>
     <xs:simpleType name='extendedtokenkey'>
       <xs:restriction base='xs:token'>
         <xs:minLength='1'/>
         <xs:maxLength='50'/>
       </xs:restriction>
     </xs:simpleType>
<!-- NAMED COMPLEX TYPE -->
  <xs:complexType name='datum'>
    <xs:sequence>
     <xs:element name='east' type='xs:int' />
     <xs:element name='north' type='xs:int' />
    </xs:sequence>
    <xs:attributeGroup ref='xs:spatialreference' use='required' />
  </xs:complexType>
<!-- ATTRIBUTE GROUP-->
  <xs:attributeGroup name='spatialreference'>
   <xs:attribute name='precision' use='required'>
     <xs:simpleType>
       <xs:restriction base='xs:positiveinteger'>
          <xs:minInclusive='1'/>
          <xs:maxInclusive='10000'/>
       </xs:restriction>
     </xs:simpleType>
   </xs:attribute>
   <xs:attribute name='projection' use='required'>
      <xs:simpleType>
        <xs:restriction base='xs:token'>
          <xs:enumeration value='OSGB'/>
          <xs:enumeration value='OSNI'/>
          <xs:enumeration value='OSI'/>
          <xs:enumeration value='WGS84'/>
          <xs:enumeration value=OSGB36'/>
        </xs:restriction>
      </xs:simpleType>
     </xs:attribute>
   <xs:/attributeGroup>
<!-- RESTRICTION TYPE -->
   <xs:simpleType name='text'>
     <xs:restriction base='string'>
       <xs:maxLength='255'/>
     </xs:restriction>
   </xs:simpleType>
</xs:schema>

Additional user defined data types

<!-- USER DEFINED LIST DATA TYPE -->
<xs:simpleType name ='list'>
  <xs:list itemType='xs:integer'/>
</xs:simpleType>

<!-- USER DEFINED LIST UNION DATA TYPE -->
<xs:element name='ELEMENTNAME' type='UNIONLIST' />
<xs:simpleType name='UNIONLIST'>
   <xs:union memberTypes='LISTTYPE1 LISTTYPE 2' />
</xs:simpleType>
<xs:simpleType name='LISTTYPE1'>
   <xs:list itemType='xs:int' />
</xs:simpleType>
<xs:simpleType name='LISTTYPE2'>
   <xs:list itemType='xs:string' />
</xs:simpleType>

<!-- USER DEFINED REGULAR EXPRESSION DATA TYPE-->
<xs:simpleType name ='regularexpression'>
  <xs:restriction base='xs:string'>
    <xs:pattern value='REGULAR EXPRESSION'/>
  </xs:restriction>
</xs:simpleType>

<!-- USER DEFINED IDENTITY CONSTRAINTS -->
<xs:unique name='Uniquekey'>
 <xs:selector xpath='ElementName'/>
 <xs:field xpath='ConstrainedNode'/>
</xs:unique>

<xs:key name='primarykey'>
 <xs:selector xpath='ElementName'/>
 <xs:field xpath='primarykeyNode'/>
</xs:key>

<xs:keyref name='foreignkey' refer='primarykey'>
 <xs:selector xpath='ElementName'/>
 <xs:field xpath='foreignkeynode'/>
</xs:keyref>

<!-- USER DEFINED NOTATION CONSTRAINTS -->
<xs:notation name='jpeg' public='image/jpeg' system='jpgviewer.exe'/>
<xs:simpleType name='imagenotation'>
  <xs:restriction base='xs:notation'>
    <xs:enumeration value='jpg'/>
  </xs:restriction>
</xs:simpleType>

Relax NG

OASIS Recommendation

http://relaxng.org

Relax NG tools

Organisation

Compact Relax NG

default namespace = "http://data.nbn.org.uk/organisation"
namespace admin = "http://data.nbn.org.uk/admin"
start = organisation
organisation = element organisation {organisationkey, logo, dataprovidername, description, administrators, postcode, website }
administrators = element administrators {administrator}+
administrator = element administrator {name, email, telephone}

organisationkey = attribute organisationkey {text}
logo = attribute logo {text}?
dataprovidername = element dataprovidername {text}
description = element description {text}?
postcode = element postcode {text}
website = element website {text}?

name = element admin:name {text}
email = element admin:email {text}
telephone = element admin:telephone {text}

Relax NG

<r:grammar xmlns ='http://data.nbn.org.uk/organisation'
           xmlns:admin='http://data.nbn.org/uk/admin'
           xmlns:r='http://relaxng.org/ns/structure/1.0'
           xmlns:a='http://relaxng.org/ns/compatibility/annotations/1.0'>
  <r:start>
    <a:documentation>Relax NG schema for organisation</a:documentation>
    <r:element name='organisation'>
       <r:attribute name='organisationkey' />
       <r:optional>
         <r:attribute name='logo' />
       </r:optional>
       <r:element name='administrators'>
          <r:oneOrMore>
            <r:element name='administrator'>
               <r:ref name='adminDetails' />
            </r:element>
          </r:oneOrMore>
       </r:element>
       <r:interleave>
         <r:element name='dataprovidername'>
           <r:text />
         <r:element>
         <r:zeroOrMore>
           <r:element name='description'>
             <r:text />
           </r:element>
         </r:zeroOrMore>
         <r:element name='postcode'>
           <r:text />
         <r:element>
         <r:zeroOrMore>
           <r:element name='website'>
             <r:text />
           </r:element>
         </r:zeroOrMore>
       </r:interleave>
    </r:element>
    <r:define name='adminDetails'>
      <r:interleave>
        <r:element name='admin:name'>
          <r:text/>
        </r:element>
        <r:element name='admin:email'>
          <r:text/>
        </r:element>
        <r:element name='admin:telephone'>
          <r:text/>
        </r:element>
      </r:interleave>
    </r:define>
  <r:start>
</r:grammar>

NBN Exchange Format

Compact Relax NG

div {
  # includes following relax NG files
  include "admin.rnc"
  include "publicaccess.rnc"
  include "metadata.rnc"
}

default namespace = "http://data.nbn.org.uk/dataset"
start = nbnexchange

div {
  #dataset
  nbnexchange = element nbnexchange {dataset, admin:administrators, access:publicaccess, meta:metadata, records }
  dataset = element dataset {datasetkey}
  datasetkey = attribute datasetkey {text}
  records = element records {record}+
  record = element record {recordkey, surveykey, samplekey, (vaguedate | date), (taxonversionkey | biotopekey), zeroabundance, sensitive, sitename, spatialreference, recorder, determiner, attributes }
}

div {
 #record
 recordkey = attribute recordkey {text}
 surveykey = element  surveykey {text}?
 samplekey = element samplekey {text}?
 vaguedate = grammar {
              start = vaguedate
              vaguedate = element vaguedate {startdate & enddate & datetype }
              startdate = element startdate {strDate}
              enddate = element enddate {strDate}
              datetype = element datetype {'D'|'DD'|'O'|'OO'|'Y'|'YY'|'-Y'|'ND'}
              }
 date = element date {text}
 taxonversionkey = element taxonversionkey {text}
 biotopekey = element biotopekey {text}
 zeroabundance = element zeroabundance {'T'|'F'}
 sensitive = element sensitive {'T'|'F'}
 sitename = element sitename {sitekey, str80}
 sitekey = attribute sitekey {text}
 spatialreference = element spatialreference {precision & projection & coordinate}
 precision = attribute precision {xsl:integer}
 projection = attribute projection {'OSGB'|'OSNI'|'WGS84'|'OSGB36'}
 coordinate |= element gridreference {strGR}
 coordinate |= element east {text}, element north {text}
 recorder = element recorder {str140}
 determiner = element determiner {str140}
 attributes = element attributes {attribute}
 attribute = element attribute {fieldname, str255}
 fieldname = attribute fieldname {text}
}
div {
 #user defined datatype patterns
 str80 = xsd:string {maxlength="80"}
 str140 = xsd:string {maxlength="140"}
 str255 = xsd:string {maxlength="255"}
 strGR = xsd:string {pattern ="REGULAR EXPRESSION"}
 strDate = xsd:string {pattern ="REGULAR EXPRESSION"}
}

# adminsitrators namespace
admin.rnc:
namespace admin = "http://data.nbn.org.uk/admin"
start = admin:administrators
administrators = element admin:administrators {administrator}+
administrator = element admin:administrator {userkey, name, email}
userkey = attribute {text}
name = element admin:name {text}
email = element admin:name {text}?

# public access namespace
publicaccess.rnc
namespace access = "http://data.nbn.org/ukaccess"
start = access:publicaccess
publicaccess = element access:publicaccess {resolution, download, attributes, sensitive, recorder, validation }
resolution = element access:resolution {'10km'|'2km'|'1km'|'100m'}
download = element access:download {'Y'|'N'}
attributes = element access:attributes {'Y'|'N'}
sensitive = element access:sensitive {'Y'|'N'}
recorder = element access:recorder {'Y'|'N'}
validation = element access:validation {'Y'|'N'}?

# metadata namespace
metadata.rnc:
namespace = "http://data.nbn.org.uk/metadata
start = meta:metadata
metadata = element meta:metadata {title, description, methods, purpose, geographic, temporal, quality, additionalinformation, accesscontraints,useconstraints }
title = meta:title {text}
description = meta:description {mixed {element i {text} | element b {text}? | element br {empty} | {text}*}
methods = meta:methods {text}
purpose = meta:purpose {text}
geographic = meta:geographic {text}
temporal = meta:temporal {text}
quality = meta:quality {text}
additionalinformation = meta:addtionalinformation {text}
accessconstraints = meta:accessconstraints {text}
useconstraints = meta:useconstraints {text}

Relax NG

<r:grammar xmlns ='http://data.nbn.org.uk/dataset'
           xmlns:admin='http://data.nbn.org/uk/admin'
           xmlns:access='http://data.nbn.org/uk/publicaccess'
           xmlns:meta='http://data.nbn.org/uk/metadata'
           xmlns:r='http://relaxng.org/ns/structure/1.0'
           xmlns:xs='http://www.w3.org/2001/XMLSchema'>
           xmlns:a='http://relaxng.org/ns/compatibility/annotations/1.0'>
  <r:start>
    <a:documentation>Relax NG schema for dataset</a:documentation>
       <r:element name='nbnexchange'>
         <r:element name='admin:admin>
           <r:externalRef href='admin.rng'/>
         </r:element>
         <r:element name='access:publicaccess'>
           <r:externalRef href='publicaccess.rng'/>
         </r:element>
         <r:element name='meta:metadata'>
           <r:externalRef href='metadata.rng'/>
         </r:element>
         <r:element name='dataset'>
            <r:attribute name='datasetkey' />
               <r:element name='records'>
                  <r:oneOrMore>
                    <r:element name='record'>
                       <r:ref name='recordDetails' />
                    </r:element>
                   </r:oneOrMore>
               </r:element>
         </r:element>
       </r:element>
       <r:define name='recordDetails'>
          <r:attribute name='recordkey' />
           <r:interleave>
            <r:optional>
               <r:element name='surveykey'>
                 <r:text />
               </r:element>
            </r:optional>
            <r:optional>
               <r:element name='samplekey'>
                 <r:text />
               </r:element>
            </r:optional>
            <r:choice>
               <r:element name='vaguedate'>
                  <r:ref='vaguedateDetails'>
               </r:element>
               <r:element ='date'>
                   <r:text />
               </r:element>
             </r:choice>
           <r:choice>
               <r:element name='taxonversionkey'>
                  <r:text />
               </r:element>
               <r:element ='biotopekey'>
                   <r:text />
               </r:element>
           </r:choice>
           <r:optional>
               <r:element name='zeroabundance'>
                 <r:data type='xs:boolean' />
               </r:element>
            </r:optional>
            <r:optional>
               <r:element name='sensitive'>
                 <r:data type='xs:boolean' />
               </r:element>
            </r:optional>
            <r:optional>
               <r:element name='sitename'>
                  <r:optional>
                    <r:attribute name='sitekey' />
                  </r:optional>
               </r:element>
            </r:optional>
             <r:element name='spatialreference'>
                  <r:ref='spatialreferenceDetails'>
             </r:element>
            <r:optional>
               <r:element name='recorder'>
                 <r:text />
               </r:element>
            </r:optional>
            <r:optional>
               <r:element name='determiner'>
                 <r:text />
               </r:element>
            </r:optional>
            <r:optional>
               <r:element name=attributes'>
                 <r:zeroOrMore>
                    <r:element name='attribute'>
                        <r:attribute name='fieldname' />  
                    </r:element>
                  </r:zeroOrMore>
               </r:element>
            </r:optional>
          </r:interleave>
       </r:define>
       <r:define name='vaguedateDetails'>
          <r:interleave>
            <r:element name='startdate'>
              <r:text/>
            </r:element>
            <r:element name='enddate'>
              <r:text/>
            </r:element>
            <r:element name='datetype'>
              <r:text/>
            </r:element>
          </r:interleave>
       </r:define>
       <r:define name='spatialreferenceDetails'>
          <r:choice>
            <r:element name='gridreference'>
              <r:text/>
            </r:element>
            <r:group>
              <r:element name='east'>
                <r:text/>
               </r:element>
               <r:element name='north'>
                <r:text/>
               </r:element>
             </r:group>
            </r:choice>
            <r:element name='precision'>
              <r:data type='xs:unsignedshort' />
            </r:element>
            <r:element name='projection'>
              <r:text/>
            </r:element>
       </r:define>
  <r:start>
</r:grammar>

Additional syntax

<r:element name='LIST'>
  <r:list>
    <r:zeroOrMore>
      <r:text/>
    </r:zerOrMore>
  </r:list>
</r:element>

<r:element name='EMPTY'>
  <r:empty />
</r:element>

<r:element name='MIXED'>
  <r:mixed>
    <r:zeroOrMore>
      <r:element name='b'>
        <r:text/>
      </r:element>
    </r:zeroOrMore>
  </r:mixed>
</r:element>

<r:element name='ANY'>
  <r:element>
   <r:anyName/>
    <r:zeroOrMore>
     <r:attribute>
       <r:anyName/>
     </r:attribute>
    </r:zeroOrMore>
   </r:element>
</r:element>

Schematron

<-- stylesheet used to convert schematron stylesheet for use on xml document -->
<xsl:stylesheet version='1.0'
                xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
                xmlns:axsl='http://www.w3.org/1999/XSL/TransformAlias'>
  <xsl:import href='skeleton1-5.xsl' <-- metastylesheet -->
  <xsl:namespace-alias stylesheet-prefix='asxl' result-prefix='xsl' />

  <--override named templates in imported meta-stylesheet -->
  <xsl:template name='process-message'>
   <axsl:message> <-- alias message element mapped to xsl namespace in result tree -->
     <xsl:apply-templates mode='text' />
   </axsl:message>
  </xsl:template>
</xsl:stylesheet>

<-- schematron stylesheet with rules -->

<sch:schema xmlns:sch='http://xml.ascc.net/resource/schematron'>
  <sch:title>Example rules</sch:title>
  <sch:pattern name='Validating Elements'>
    <sch:rule context='XPATH|ELEMENT'>

      <-- Check name of document element -->
       <sch:report test='ELEMENTNAME'> <-- returns message if true -->
          The <sch:name /> element is the document element
       </sch:report>
       <sch:assert test='parent::*'> <-- returns message if false -->
          The <sch:name /> element is the document element
       </sch:assert>

      <-- check child nodes of element -->
       <sch:report test='node()'>
          The <sch:name /> element has child nodes
       </sch:report>
       <sch:report test='* or text()'>
          The <sch:name /> element has child nodes containing text
       </sch:report>
       <sch:report test='text()[normalize-space()]'>
          The <sch:name /> element has child nodes containing whitespace only text
       </sch:report>
       <sch:report test='string()'>
          The <sch:name /> element has child nodes containing text
       </sch:report'>
       <sch:report test='* or comment() or processing-instruction()'>
          The <sch:name /> element has comment or processing instructions child nodes
       </sch:report>
       <sch:report test='*'>
          The <sch:name /> element has child elements
       </sch:report>
       <sch:assert test='CHILDELEMENTNAME'>
          The <sch:name /> element does not have child elements named CHILDELEMENTNAME
       </sch:assert>
       <sch:assert test='count(CHILDELEMENTNAME) &lt; NUMBER)'>
          The <sch:name /> element does not contain less than NUMBER CHILDELEMENTNAME elements
       </sch:assert>
       <sch:report test='*[not(self::CHILDELEMENTNAME1 or self::CHILDELEMENTNAME2]'>
          The <sch:name /> element contains child elements other than CHILDELEMENTNAME 1 AND 2
       </sch:report>
       <sch:report test='*[namespace-uri()]'>
          The <sch:name /> element contains child elements in a namespace
       </sch:report>
       <sch:report test='XMLNS:*[not(XMLNS:CHILDELEMENTNAME)]'>
          The <sch:name /> element contains child elements in a XMLNS namespace which are not CHILDELEMENTNAME
       </sch:report>
       <sch:assert test='*[1][self::CHILDELEMENTNAME)]'>
          The <sch:name /> element has first child element named CHILDELEMENTNAME
       </sch:assert>
       <sch:assert test='*[1][self::CHILDELEMENTNAME)]'>
          The <sch:name /> element does not have a first child element named CHILDELEMENTNAME
       </sch:assert>
       <sch:assert test='CHILDELEMENTNAME1/following-sibling::*[1][self::CHILDELEMENTNAME2)]>
          The <sch:name /> element does not have CHILDELEMENTNAME2 following CHILDELEMENTNAME1
       </sch:assert>
       <sch:assert test='CHILDELEMENTNAME1/preceding-sibling::*[1][self::CHILDELEMENTNAME2)]>
          The <sch:name /> element does not have CHILDELEMENTNAME2 preceding CHILDELEMENTNAME1
       </sch:assert>
       <sch:report test='ELEMENTNAME1 or ELEMENTNAME2' and not(ELEMENTNAME1 and ELEMENTNAME2)'>
          The <sch:name /> element contains either ELEMENTNAME1 and ELEMENTNAME2 elements but not both
       </sch:report>
       <sch:report test='ELEMENTNAME1[not preceding-sibling::*[1]) or preceding-sibling::*[1][self::ELEMENTNAME1]]'>
          The <sch:name /> element contains only ELEMENTNAME1 elements
       </sch:report>
       <sch:report test='count(ELEMENTNAME1[preceding-sibling::*[1][self::ELEMENTNAME1]]) + 1 = count(ELEMENTNAME1)'>
          The <sch:name /> element contains only ELEMENTNAME1 elements
       </sch:report>
       <sch:report test='ELEMENTNAME2/preceding-sibling::ELEMENTNAME1 and ELEMENTNAME2/following-sibling::ELEMENTNAME1'>
          The <sch:name /> element contains ELEMENTNAME2 elements in the middle of ELEMENTNAME1
       </sch:report>
       </sch:rule>
  </sch:pattern>
  <sch:pattern name='Validating Attributes'>
    <sch:rule context='XPATH|ELEMENT'>
       <sch:report test='@ATTRIBUTENAME'>
          The <sch:name /> element has attribute ATTRIBUTENAME
       </sch:report>
       <sch:report test="@*[not(name()='ATTRIBUTENAME1' or name()='ATTRIBUTENAME2')]">
          The <sch:name /> element does not contain attributes ATTRIBUTENAME1 or ATTRIBUTENAME2
       </sch:report>
       <sch:report test="@*[not(local-name()='PREFIX' and namespace-uri()='http//www.example.com')]">
          The <sch:name /> element does not contain attributes in example:PREFIX namespace
       </sch:report>
       <sch:assert test='@*[not(namespace-uri())]'>
          The <sch:name /> element has attributes in no namespace
       </sch:assert>
    </sch:rule>
  </sch:pattern>
  <sch:pattern name='Validating strings'>
    <sch:rule context='XPATH|ELEMENT'>
        <sch:assert test="normalize-space()='VALUE'">
          The <sch:name /> element does not have value of VALUE
       </sch:assert>
        <sch:assert test="translate(normalize-space(), 'VALUE', 'value') ='value'">
          The <sch:name /> element does not have value of VALUE irrespective of case sensitivity
       </sch:assert>
        <sch:assert test='number()=NUMBER'>
          The <sch:name /> element does not have a numberic value of NUMBER
       </sch:assert>
       <sch:assert test="number()=number()">
          The <sch:name /> element does not have a numberic value
       </sch:assert>
        <sch:assert test='string-length()>= MINNUMBER and MAXNUMBER >= string-length()'>
          The <sch:name /> element does not have a numberic value between MINNUMBER and MAXNUMBER
       </sch:assert>
        <sch:assert test="string()">
          The <sch:name /> element is empty
       </sch:assert>
        <sch:assert 
            test="substring(.,7,4)=floor(substring(.,7,4)) and  <-- YYYY is numberic -->
                  substring(.,4,2)=floor(substring(.,4,2)) and
                  substring(.,4,2)>=1 and 12 >= substring(.,4,2) <-- MM is numberic between 1 to 12 -->
                  substring(.,1,2)=floor(substring(.,1,2)) and
                  substring(.,1,2)>=1 and 31 >= substring(.,1,2) <-- DD is numberic between 1 to 31 -->
                  substring(.,3,1)='/' and substring(.,6,1)='/'">
          The <sch:name /> element is not a valid date DD/MM/YYYY
       </sch:assert>
       <sch:assert test="number()=number()">
          The <sch:name /> element is empty
       </sch:assert>
    </sch:rule>
  </sch:pattern>
  <sch:pattern name='Co-occurrence constraints'>
    <sch:assert context='XPATH|ELEMENT'>
         test="ELEMENTNAME1='10000' and ELEMENTNAME2='OSGB" and string-length([ELEMENTNAME3])='4'">
          The <sch:name /> element does not contain a validate 10km gridreference
    </sch:assert>
  </sch:pattern>
  <sch:pattern name='Keys and References'>
    <sch:rule context='XPATH|ELEMENT'>
        <sch:key name='KEYNAME' path="concat(ELEMENTNAME1, '-', ELEMENTNAME2)" />
        <sch:assert test="count(key('KEYNAME', concat(ELEMENTNAME1, '-', ELEMENTNAME2)))=1'>
             The <sch:name /> element contains duplicate KEYNAME
        </sch:assert>
        <sch:key name='KEYNAME' path='@id' />
        <sch:report test="string(ELEMENTNAME) and not (key('KEYNAME', ELEMENTNAME))">
           The <sch:name /> element is not the same as the KEYNAME id value
        </sch:report>
    </sch:rule>
  </sch:pattern>
</sch:schema>

page_revision: 28, last_edited: 1256670130|%e %b %Y, %H:%M %Z (%O ago)
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License