RELAX: Schemas Don't Have to be Hard

Elliotte Rusty Harold

Software Development 2005 West

Friday, March 17, 2006

elharo@metalab.unc.edu

http://www.cafeconleche.org/


What are Schemas?


About RELAX NG


What's Wrong with DTDs?


What's Wrong with W3C XML Schema Language?


greeting.xml

<?xml version="1.0"?>
<GREETING>
Hello XML!
</GREETING>

greeting.rng

<?xml version="1.0"?>
<element name="GREETING" xmlns="http://relaxng.org/ns/structure/1.0">
  <text/>
</element>

Validating the document with Jing

$ jing greeting.rng greeting.xml


An Invalid Document

<?xml version="1.0"?>
<GREETING>
  <P>Hello XML!</P>
</GREETING>

Checking the Invalid Document

$ jing  greeting.rng greeting3.xml
/Users/elharo/Documents/speaking/sd2006west/relaxng/examples/greeting3.xml:
3:6: error: unknown element "P"

RELAX NG Validators


The compact syntax: greeting.rnc

element GREETING { text }

A More Complex Document

<?xml version="1.0"?>
<SONG>
  <TITLE>Hot Cop</TITLE>
  <COMPOSER>Jacques Morali</COMPOSER>
  <COMPOSER>Henri Belolo</COMPOSER>
  <COMPOSER>Victor Willis</COMPOSER>
  <PRODUCER>Jacques Morali</PRODUCER>
  <PUBLISHER>PolyGram Records</PUBLISHER>
  <LENGTH>6:20</LENGTH>
  <YEAR>1978</YEAR>
  <ARTIST>Village People</ARTIST>  
</SONG>

A More Complex Schema

<?xml version="1.0"?>
<element name="SONG" xmlns="http://relaxng.org/ns/structure/1.0">
  <element name="TITLE">
    <text/>
  </element>
  <element name="COMPOSER">
    <text/>
  </element>
  <element name="COMPOSER">
    <text/>
  </element>
  <element name="COMPOSER">
    <text/>
  </element>
  <element name="PRODUCER">
    <text/>
  </element>
  <element name="PUBLISHER">
     <text/>
  </element>
  <element name="LENGTH">
    <text/>
  </element>
  <element name="YEAR">
    <text/>
  </element>
  <element name="ARTIST">
    <text/>
  </element>
</element>

element SONG {
  element TITLE     { text },
  element COMPOSER  { text },
  element COMPOSER  { text },
  element COMPOSER  { text },
  element PRODUCER  { text },
  element PUBLISHER { text },
  element LENGTH    { text },
  element YEAR      { text },
  element ARTIST    { text }
}

Groups


A More Flexible Schema

<?xml version="1.0"?>
<element name="SONG" xmlns="http://relaxng.org/ns/structure/1.0">
  <element name="TITLE">
    <text/>
  </element>
  <oneOrMore>
    <element name="COMPOSER">
      <text/>
    </element>
  </oneOrMore>
  <zeroOrMore>
    <element name="PRODUCER">
      <text/>
    </element>
  </zeroOrMore>
  <optional>
    <element name="PUBLISHER">
      <text/>
    </element>
  </optional>
  <optional>
    <element name="LENGTH">
      <text/>
    </element>
  </optional>
  <optional>
    <element name="YEAR">
      <text/>
    </element>
  </optional>
  <oneOrMore>
    <element name="ARTIST">
      <text/>
    </element>
  </oneOrMore>
</element>

element SONG {
  element TITLE     { text },
  element COMPOSER  { text }+,
  element PRODUCER  { text }*,
  element PUBLISHER { text }?,
  element LENGTH    { text }?,
  element YEAR      { text }?,
  element ARTIST    { text }+
}

A Couple of Notes


Element Content

<?xml version="1.0"?>
<SONG>
  <TITLE>Hot Cop</TITLE>
  <COMPOSER>
    <NAME>
      <GIVEN>Jacques</GIVEN>
      <FAMILY>Morali</FAMILY>
    </NAME>
  </COMPOSER>
  <COMPOSER>
    <NAME>
      <GIVEN>Henri</GIVEN>
      <FAMILY>Belolo</FAMILY>
    </NAME>
  </COMPOSER>
  <COMPOSER>
    <NAME>
      <GIVEN>Victor</GIVEN>
      <FAMILY>Willis</FAMILY>
    </NAME>
  </COMPOSER>
  <PRODUCER>
    <NAME>
      <GIVEN>Jacques</GIVEN>
      <FAMILY>Morali</FAMILY>
    </NAME>
  </PRODUCER>
  <PUBLISHER>PolyGram Records</PUBLISHER>
  <YEAR>1978</YEAR>
  <ARTIST>Village People</ARTIST>  
</SONG>

Nested structures

<?xml version="1.0"?>
<element name="SONG" xmlns="http://relaxng.org/ns/structure/1.0">
  <element name="TITLE">
    <text/>
  </element>
  <oneOrMore>
    <element name="COMPOSER">
      <element name="NAME">
        <element name="GIVEN">
          <text/>
        </element>
        <element name="FAMILY">
          <text/>
        </element>
      </element>
    </element>
  </oneOrMore>
  <zeroOrMore>
    <element name="PRODUCER">
      <element name="NAME">
        <element name="GIVEN">
          <text/>
        </element>
        <element name="FAMILY">
          <text/>
        </element>
      </element>
    </element>
  </zeroOrMore>
  <optional>
    <element name="PUBLISHER">
      <text/>
    </element>
  </optional>
  <optional>
    <element name="LENGTH">
      <text/>
    </element>
  </optional>
  <optional>
    <element name="YEAR">
      <text/>
    </element>
  </optional>
  <oneOrMore>
    <element name="ARTIST">
      <text/>
    </element>
  </oneOrMore>
</element>

Nested structures in the Compact syntax

element SONG {
  element TITLE { text },
  element COMPOSER {
    element NAME {
      element GIVEN { text },
      element FAMILY { text }
    }
  }+,
  element PRODUCER {
    element NAME {
      element GIVEN { text },
      element FAMILY { text }
    }
  }*,
  element PUBLISHER { text }?,
  element LENGTH { text }?,
  element YEAR { text }?,
  element ARTIST { text }+
}

Sharing Content Models

<?xml version="1.0"?>
<grammar xmlns="http://relaxng.org/ns/structure/1.0">

  <start>
  
    <element name="SONG">
      <element name="TITLE">
        <text/>
      </element>
      
      <oneOrMore>
        <element name="COMPOSER">
          <ref name="personContent"/>
        </element>
      </oneOrMore>
      
      <zeroOrMore>
        <element name="PRODUCER">
          <ref name="personContent"/>
        </element>
      </zeroOrMore>
      
      <optional>
        <element name="PUBLISHER">
          <text/>
        </element>
      </optional>
      <optional>
        <element name="LENGTH">
          <text/>
        </element>
      </optional>
      <optional>
        <element name="YEAR">
          <text/>
        </element>
      </optional>
      <oneOrMore>
        <element name="ARTIST">
          <text/>
        </element>
      </oneOrMore>
    </element>
    
  </start>

  <define name="personContent">
    <element name="NAME">
      <element name="GIVEN">
        <text/>
      </element>
      <element name="FAMILY">
        <text/>
      </element>
    </element>
  </define>

</grammar>

Or in the compact syntax

start =
  element SONG {
    element TITLE     { text },
    element COMPOSER  { personContent }+,
    element PRODUCER  { personContent }*,
    element PUBLISHER { text }?,
    element LENGTH    { text }?,
    element YEAR      { text }?,
    element ARTIST    { text }+
  }
personContent =
  element NAME {
    element GIVEN  { text },
    element FAMILY { text }
  }

When Order Doesn't Matter

<?xml version="1.0"?>
<SONG>
  <TITLE>Hot Cop</TITLE>
  <ARTIST>Village People</ARTIST>  
  <YEAR>1978</YEAR>
  <COMPOSER>
    <NAME><FAMILY>Morali</FAMILY> <GIVEN>Jacques</GIVEN></NAME>
  </COMPOSER>
  <COMPOSER>
    <NAME><GIVEN>Henri</GIVEN> <FAMILY>Belolo</FAMILY></NAME>
  </COMPOSER>
  <PRODUCER>
    <NAME><GIVEN>Jacques</GIVEN> <FAMILY>Morali</FAMILY></NAME>
  </PRODUCER>
  <COMPOSER>
    <NAME><FAMILY>Willis</FAMILY> <GIVEN>Victor</GIVEN></NAME>
  </COMPOSER>
  <PUBLISHER>PolyGram Records</PUBLISHER>
</SONG>

interleave

<?xml version="1.0"?>
<grammar xmlns="http://relaxng.org/ns/structure/1.0">

  <start>
  
    <element name="SONG">
      <element name="TITLE">
        <text/>
      </element>
      <interleave>
          
          <oneOrMore>
            <element name="COMPOSER">
              <ref name="personContent"/>
            </element>
          </oneOrMore>
          
          <zeroOrMore>
            <element name="PRODUCER">
              <ref name="personContent"/>
            </element>
          </zeroOrMore>
          
          <optional>
            <element name="PUBLISHER">
              <text/>
            </element>
          </optional>
          <optional>
            <element name="LENGTH">
              <text/>
            </element>
          </optional>
          <optional>
            <element name="YEAR">
              <text/>
            </element>
          </optional>
          <oneOrMore>
            <element name="ARTIST">
              <text/>
            </element>
          </oneOrMore>
      </interleave>
    </element>
    
  </start>

  <define name="personContent">
    <element name="NAME">
      <interleave>
      <element name="GIVEN">
        <text/>
      </element>
      <element name="FAMILY">
        <text/>
      </element>
      </interleave>
    </element>
  </define>

</grammar>

start =
  element SONG {
    element TITLE        { text },
    (element COMPOSER    { personContent }+
     & element PRODUCER  { personContent }*
     & element PUBLISHER { text }?
     & element LENGTH    { text }?
     & element YEAR      { text }?
     & element ARTIST    { text }+)
  }
personContent =
  element NAME {
    element GIVEN    { text }
    & element FAMILY { text }
  }

In the compact Syntax

start =
  element SONG {
    element TITLE        { text },
    (element COMPOSER    { personContent }+
     & element PRODUCER  { personContent }*
     & element PUBLISHER { text }?
     & element LENGTH    { text }?
     & element YEAR      { text }?
     & element ARTIST    { text }+)
  }
personContent =
  element NAME {
    element GIVEN    { text }
    & element FAMILY { text }
  }

Mixed Content

<?xml version="1.0"?>
<SONG>
  <TITLE>Hot Cop</TITLE>
  <COMPOSER>
    <NAME><GIVEN>Jacques</GIVEN><FAMILY>Morali</FAMILY></NAME>
  </COMPOSER>
  <COMPOSER>
    <NAME><GIVEN>Henri</GIVEN><FAMILY>Belolo</FAMILY></NAME>
  </COMPOSER>
  <COMPOSER>
    <NAME><GIVEN>Victor</GIVEN><FAMILY>Willis</FAMILY></NAME>
  </COMPOSER>
  <PRODUCER>
    <NAME><GIVEN>Jacques</GIVEN><FAMILY>Morali</FAMILY></NAME>
  </PRODUCER>
  <PUBLISHER>PolyGram Records</PUBLISHER>
  <YEAR>1978</YEAR>
  <ARTIST>Village People</ARTIST>
  <DESCRIPTION>
    <PERSON>Victor Willis</PERSON>'s theme song is 
    one of the lesser known of the 
    <ARTIST>Village People</ARTIST>'s <IRONIC>hits</IRONIC>, 
    and <OPINION>deservedly so</OPINION>. It never 
    charted, <!-- need to verify this? --> 
    but the group didn't have enough genuine 
    hits to fill a Best Of album, <OPINION>so some  
    lesser numbers had to be <METAPHOR>pulled out of the  
    recycle bin</METAPHOR></OPINION>. 
  </DESCRIPTION>
</SONG>

Declaring Mixed Content

...
          <optional>
            <element name="DESCRIPTION">
              <interleave>
                <text />
                <zeroOrMore>
                  <element name="PERSON">
                    <text/>
                  </element>
                </zeroOrMore>
                <zeroOrMore>
                  <element name="ARTIST">
                    <text/>
                  </element>
                </zeroOrMore>
                <zeroOrMore>
                  <element name="IRONIC">
                    <text/>
                  </element>
                </zeroOrMore>
                <zeroOrMore>
                  <element name="OPINION">
                    <interleave>
                      <text/>
                      <zeroOrMore>
                        <element name="METAPHOR">
                          <text/>
                        </element>
                      </zeroOrMore>
                    </interleave>
                  </element>
                </zeroOrMore>
              </interleave>
            </element>
          </optional>

start =
  element SONG {
    element TITLE { text },
    (element COMPOSER { personContent }+
     & element PRODUCER { personContent }*
     & element PUBLISHER { text }?
     & element LENGTH { text }?
     & element YEAR { text }?
     & element ARTIST { text }+
     & element DESCRIPTION {
         text
         & element PERSON { text }*
         & element ARTIST { text }*
         & element IRONIC { text }*
         & element OPINION {
             text
             & element METAPHOR { text }*
           }*
       }?)
  }
personContent =
  element NAME {
    element GIVEN { text },
    element FAMILY { text }
  }

Choices

A song must have at least one of ARTIST, COMPOSER, or PRODUCER:

start =
  element SONG {
    element TITLE       { text },
    (element COMPOSER   { personContent }
     | element PRODUCER { personContent }
     | element ARTIST   { text })+,
    element PUBLISHER   { text }?,
    element LENGTH      { text }?,
    element YEAR        { text }?
  }
personContent =
  element NAME {
    element GIVEN    { text }
    & element FAMILY { text }
  }

Choices in the XML Syntax

start =
  element SONG {
    element TITLE       { text },
    (element COMPOSER   { personContent }
     | element PRODUCER { personContent }
     | element ARTIST   { text })+,
    element PUBLISHER   { text }?,
    element LENGTH      { text }?,
    element YEAR        { text }?
  }
personContent =
  element NAME {
    element GIVEN    { text }
    & element FAMILY { text }
  }

Groups

Allow a NAME element to contain either plain text or a GIVEN and a FAMILY but not both:

<element name="NAME>
  <choice>
    <text/>
    <group>
       <interleave>
         <element name="GIVEN">
           <text/>
         </element>
         <element name="FAMILY">
           <text/>
         </element>
       </interleave>
    </group>
  </choice>
</element>

Use Parentheses for Groups in the Compact Syntax

personContent =
  element NAME {
    (element GIVEN { text } & element FAMILY { text })
    |
    text
  }

A Document with Attributes

<?xml version="1.0"?>
<SONG>
  <TITLE>Hot Cop</TITLE>
  <PHOTO ALT="Victor Willis in Cop Outfit" WIDTH="100" HEIGHT="200"/>
  <COMPOSER>Jacques Morali</COMPOSER>
  <COMPOSER>Henri Belolo</COMPOSER>
  <COMPOSER>Victor Willis</COMPOSER>
  <PRODUCER>Jacques Morali</PRODUCER>
  <PUBLISHER>PolyGram Records</PUBLISHER>
  <YEAR>1978</YEAR>
  <ARTIST>Village People</ARTIST>  
</SONG>

Declaring Attributes

<?xml version="1.0"?>
<element name="SONG" xmlns="http://relaxng.org/ns/structure/1.0">
  <element name="TITLE">
    <text/>
  </element>
  <element name="PHOTO">
    <attribute name="ALT">
      <text/>
    </attribute>
    <attribute name="WIDTH">
      <text/>
    </attribute>
    <attribute name="HEIGHT">
      <text/>
    </attribute>
  </element>
  <oneOrMore>
    <element name="COMPOSER">
      <text/>
    </element>
  </oneOrMore>
  <zeroOrMore>
    <element name="PRODUCER">
      <text/>
    </element>
  </zeroOrMore>
  <optional>
    <element name="PUBLISHER">
      <text/>
    </element>
  </optional>
  <optional>
    <element name="LENGTH">
      <text/>
    </element>
  </optional>
  <optional>
    <element name="YEAR">
      <text/>
    </element>
  </optional>
  <oneOrMore>
    <element name="ARTIST">
      <text/>
    </element>
  </oneOrMore>
</element>

element SONG {
  element TITLE { text },
  element PHOTO {
    attribute ALT    { text },
    attribute WIDTH  { text },
    attribute HEIGHT { text }
  },
  element COMPOSER  { text }+,
  element PRODUCER  { text }*,
  element PUBLISHER { text }?,
  element LENGTH    { text }?,
  element YEAR      { text }?,
  element ARTIST    { text }+
}

Enumerations

The publisher must be one of the oligopoly that controls 90% of U.S. music (Warner-Elektra-Atlantic, Universal Music Group, Sony Music Entertainment, Inc., Capitol Records, Inc., BMG Music)

<?xml version="1.0"?>
<element name="SONG" xmlns="http://relaxng.org/ns/structure/1.0">
  <element name="TITLE">
    <text/>
  </element>
  <oneOrMore>
    <element name="COMPOSER">
      <text/>
    </element>
  </oneOrMore>
  <zeroOrMore>
    <element name="PRODUCER">
      <text/>
    </element>
  </zeroOrMore>
  <optional>
    <element name="PUBLISHER">
    <choice>
      <value>Warner-Elektra-Atlantic</value>
      <value>Universal Music Group</value>
      <value>Sony Music Entertainment, Inc.</value>
      <value>Capitol Records, Inc.</value>
      <value>BMG Music</value>
    </choice>
  </element>
  </optional>
  <optional>
    <element name="LENGTH">
      <text/>
    </element>
  </optional>
  <optional>
    <element name="YEAR">
      <text/>
    </element>
  </optional>
  <oneOrMore>
    <element name="ARTIST">
      <text/>
    </element>
  </oneOrMore>
</element>

element SONG {
  element TITLE    { text },
  element COMPOSER { text }+,
  element PRODUCER { text }*,
  element PUBLISHER {
    "Warner-Elektra-Atlantic"
    | "Universal Music Group"
    | "Sony Music Entertainment, Inc."
    | "Capitol Records, Inc."
    | "BMG Music"
  }?,
  element LENGTH { text }?,
  element YEAR   { text }?,
  element ARTIST { text }+
}

Namespaces


Default Namespace

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<SONG xmlns="http://www.cafeconleche.org/namespace/song">
  <TITLE>Hot Cop</TITLE>
  <PHOTO ALT="Victor Willis in Cop Outfit" WIDTH="100" HEIGHT="200"/>
  <COMPOSER>Jacques Morali</COMPOSER>
  <COMPOSER>Henri Belolo</COMPOSER>
  <COMPOSER>Victor Willis</COMPOSER>
  <PRODUCER>Jacques Morali</PRODUCER>
  <PUBLISHER>PolyGram Records</PUBLISHER>
  <YEAR>1978</YEAR>
  <ARTIST>Village People</ARTIST>  
</SONG>

A Schema for a Document that uses Namespaces

<?xml version="1.0"?>
<element xmlns="http://relaxng.org/ns/structure/1.0"
         name="SONG" 
         ns="http://www.cafeconleche.org/namespace/song">
  <element name="TITLE">
    <text/>
  </element>
  <element name="PHOTO">
    <attribute name="ALT">
      <text/>
    </attribute>
    <attribute name="WIDTH">
      <text/>
    </attribute>
    <attribute name="HEIGHT">
      <text/>
    </attribute>
  </element>
  <oneOrMore>
    <element name="COMPOSER">
      <text/>
    </element>
  </oneOrMore>
  <zeroOrMore>
    <element name="PRODUCER">
      <text/>
    </element>
  </zeroOrMore>
  <optional>
    <element name="PUBLISHER">
      <text/>
    </element>
  </optional>
  <optional>
    <element name="LENGTH">
      <text/>
    </element>
  </optional>
  <optional>
    <element name="YEAR">
      <text/>
    </element>
  </optional>
  <oneOrMore>
    <element name="ARTIST">
      <text/>
    </element>
  </oneOrMore>
</element>

default namespace = "http://www.cafeconleche.org/namespace/song"

element SONG {
  element TITLE { text },
  element PHOTO {
    attribute ALT    { text },
    attribute WIDTH  { text },
    attribute HEIGHT { text }
  },
  element COMPOSER  { text }+,
  element PRODUCER  { text }*,
  element PUBLISHER { text }?,
  element LENGTH    { text }?,
  element YEAR      { text }?,
  element ARTIST    { text }+
}

A Prefixed Schema for a Document that uses Namespaces

<?xml version="1.0"?>
<element xmlns="http://relaxng.org/ns/structure/1.0"
         name="sng:SONG" 
         xmlns:sng="http://www.cafeconleche.org/namespace/song">
  <element name="sng:TITLE">
    <text/>
  </element>
  <element name="sng:PHOTO">
    <attribute name="ALT">
      <text/>
    </attribute>
    <attribute name="WIDTH">
      <text/>
    </attribute>
    <attribute name="HEIGHT">
      <text/>
    </attribute>
  </element>
  <oneOrMore>
    <element name="sng:COMPOSER">
      <text/>
    </element>
  </oneOrMore>
  <zeroOrMore>
    <element name="sng:PRODUCER">
      <text/>
    </element>
  </zeroOrMore>
  <optional>
    <element name="sng:PUBLISHER">
      <text/>
    </element>
  </optional>
  <optional>
    <element name="sng:LENGTH">
      <text/>
    </element>
  </optional>
  <optional>
    <element name="sng:YEAR">
      <text/>
    </element>
  </optional>
  <oneOrMore>
    <element name="sng:ARTIST">
      <text/>
    </element>
  </oneOrMore>
</element>

namespace sng = "http://www.cafeconleche.org/namespace/song"

element sng:SONG {
  element sng:TITLE { text },
  element sng:PHOTO {
    attribute ALT    { text },
    attribute WIDTH  { text },
    attribute HEIGHT { text }
  },
  element sng:COMPOSER  { text }+,
  element sng:PRODUCER  { text }*,
  element sng:PUBLISHER { text }?,
  element sng:LENGTH    { text }?,
  element sng:YEAR      { text }?,
  element sng:ARTIST    { text }+
}

Namespaces on Attributes

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<SONG xmlns="http://www.cafeconleche.org/namespace/song"
      xmlns:xlink="http://www.w3.org/1999/xlink">
  <TITLE>Hot Cop</TITLE>
  <PHOTO xlink:type="simple" xlink:href="hotcop.jpg"
         xlink:actuate="onLoad" xlink:show="embed"
    ALT="Victor Willis in Cop Outfit" WIDTH="100" HEIGHT="200"/>
  <COMPOSER>Jacques Morali</COMPOSER>
  <COMPOSER>Henri Belolo</COMPOSER>
  <COMPOSER>Victor Willis</COMPOSER>
  <PRODUCER>Jacques Morali</PRODUCER>
  <PUBLISHER>PolyGram Records</PUBLISHER>
  <YEAR>1978</YEAR>
  <ARTIST>Village People</ARTIST>  
</SONG>

Attaching a namespace to an attribute

<?xml version="1.0"?>
<element xmlns="http://relaxng.org/ns/structure/1.0"
         name="SONG" 
         ns="http://www.cafeconleche.org/namespace/song">
  <element name="TITLE">
    <text/>
  </element>
  <element name="PHOTO">
    <attribute name="ALT">
      <text/>
    </attribute>
    <attribute name="WIDTH">
      <text/>
    </attribute>
    <attribute name="HEIGHT">
      <text/>
    </attribute>
    <attribute name="type" ns="http://www.w3.org/1999/xlink">
      <text/>
    </attribute>
    <attribute name="href" ns="http://www.w3.org/1999/xlink">
      <text/>
    </attribute>
    <attribute name="actuate" ns="http://www.w3.org/1999/xlink">
      <text/>
    </attribute>
    <attribute name="show" ns="http://www.w3.org/1999/xlink">
      <text/>
    </attribute>
  </element>
  <oneOrMore>
    <element name="COMPOSER">
      <text/>
    </element>
  </oneOrMore>
  <zeroOrMore>
    <element name="PRODUCER">
      <text/>
    </element>
  </zeroOrMore>
  <optional>
    <element name="PUBLISHER">
      <text/>
    </element>
  </optional>
  <optional>
    <element name="LENGTH">
      <text/>
    </element>
  </optional>
  <optional>
    <element name="YEAR">
      <text/>
    </element>
  </optional>
  <oneOrMore>
    <element name="ARTIST">
      <text/>
    </element>
  </oneOrMore>
</element>

default namespace = "http://www.cafeconleche.org/namespace/song"
namespace ns1 = "http://www.w3.org/1999/xlink"

element SONG {
  element TITLE { text },
  element PHOTO {
    attribute ALT    { text },
    attribute WIDTH  { text },
    attribute HEIGHT { text },
    
    attribute ns1:type    { text },
    attribute ns1:href    { text },
    attribute ns1:actuate { text },
    attribute ns1:show    { text }
  },
  element COMPOSER  { text }+,
  element PRODUCER  { text }*,
  element PUBLISHER { text }?,
  element LENGTH    { text }?,
  element YEAR      { text }?,
  element ARTIST    { text }+
}

Data Typing

Consider this document:

<foo>
    <value>45.67</value>
</foo>

What is the type of value?


Possible types

Other interpretations are doubtless possible, and even make sense in particular contexts. There's no guarantee that the string 45.67 in fact represents any particular type.


RELAX NG type libraries


data element

<?xml version="1.0"?>
<element name="SONG" xmlns="http://relaxng.org/ns/structure/1.0"
datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
  <element name="TITLE">
    <text/>
  </element>
  <interleave>

    <oneOrMore>
      <element name="COMPOSER">
        <data type="string"/>
      </element>
    </oneOrMore>
    <zeroOrMore>
      <element name="PRODUCER">
        <data type="string"/>
      </element>
    </zeroOrMore>
    <oneOrMore>
      <element name="ARTIST">
        <data type="string"/>
      </element>
    </oneOrMore>
  
  <optional>
    <element name="PUBLISHER">
      <data type="string"/>
    </element>
  </optional>
  <optional>
    <element name="LENGTH">
      <data type="string"/>
    </element>
  </optional>
  <optional>
    <element name="YEAR">
      <data type="gYear" />
    </element>
  </optional>

  <element name="PRICE">
    <data type="string">
      <param name="pattern">\p{Sc}\p{Nd}+(\.\p{Nd}\p{Nd})?</param>
    </data>
  </element>
  </interleave>
</element> 

namespace ns1 = "http://www.w3.org/1999/xhtml"

element SONG {
  element TITLE        { text },
  (element COMPOSER    { xsd:string }+
   & element PRODUCER  { xsd:string }*
   & element ARTIST    { xsd:string }+
   & element PUBLISHER { xsd:string }?
   & element LENGTH    { xsd:string }?
   & element YEAR      { xsd:gYear }?
   & element PRICE {
       xsd:string { pattern = "\p{Sc}\p{Nd}+(\.\p{Nd}\p{Nd})?" }
     })
}

Primitive Data Types for Schemas


Numeric Data Types for Schemas

XML Schema Built-In Numeric Simple Types
Name Type Examples
float IEEE 754 32-bit floating point number -INF, -1E4, -0, 0, 12.78E-2, 12, INF, NaN
double IEEE 754 64-bit floating point number -INF, 1.401E-90, -1E4, -0, 0, 12.78E-2, 12, INF, NaN, 3.4E42
decimal arbitrary precision, decimal numbers -2.7E400, 5.7E-444, -3.1415292, 0, 7.8, 90200.76, 3.4E1024
integer an arbitrarily large or small integer -500000000000000000000000, -9223372036854775809, -126789, -1, 0, 1, 5, 23, 42, 126789, 9223372036854775808, 456734987324983264987362495809587095720978
nonPositiveInteger an integer less than or equal to zero 0, -1, -2, -3, -4, -5, ...
negativeInteger an integer strictly less than zero -1, -2, -3, -4, -5, ...
long an eight-byte two's complement integer such as Java's long type -9223372036854775808, -12678967543233, -1, 9223372036854775807
int an integer that can be represented as a four-byte, two's complement number such as Java's int type -2147483648, -1, 0, 1, 5, 23, 42, 2147483647
short an integer that can be represented as a two-byte, two's complement number such as Java's short type -32768, -1, 0, 1, 5, 23, 42, 32767
byte an integer that can be represented as a one-byte, two's complement number such as Java's byte type -128, -1, 0, 1, 5, 23, 42, 127
nonNegativeInteger an integer greater than or equal to zero 0, 1, 2, 3, 4, 5, ...
unsignedLong an eight-byte unsigned integer 0, 1, 2, 3, 4, 5, ...18446744073709551614, 18446744073709551615
unsignedInt a four-byte unsigned integer 0, 1, 2, 3, 4, 5, ...4294967294, 4294967295
unsignedShort a two-byte unsigned integer 0, 1, 2, 3, 4, 5, ...65534, 65535
unsignedByte a one-byte unsigned integer 0, 1, 2, 3, 4, 5, ...254, 255
positiveInteger an integer strictly greater than zero 1, 2, 3, 4, 5, 6, ...

Time Data Types for Schemas

XML Schema Built-In Time Simple Types
Name Type Examples
dateTime a particular moment in Coordinated Universal Time; up to an arbitrarily small fraction of a second 1999-05-31T13:20:00.000-05:00
gMonth A given month in a given year 2000-10
gYear a given year 2000
gMonthDay a date in no particular year, or rather in every year --10-31
gDay a day in no particular month, or rather in every month ----31
duration a length of time, without fixed endpoints, to an arbitrary fraction of a second P2000Y10M31DT09H32M7.4312S
date a specific day in history 2000-10-31
time a specific time of day, that recurs every day 14:30:00.000, 09:30:00.000-05:00

XML Data Types for Schemas

XML Schema Built-In XML Simple Types
Name Type Examples
ID XML 1.0 ID attribute type any XML name that's unique among ID type attributes
IDREF XML 1.0 IDREF attribute type any XML name that's used as an ID type attribute elsewhere in the document
ENTITY XML 1.0 ENTITY attribute type any XML name that's declared as an unparsed entity in the DTD
NOTATION ???? ????
language Permissible values for xml:lang as defined in XML 1.0 en-GB, en-US, fr
IDREFS XML 1.0 IDREFS attribute type a white space separated list of IDREF names
ENTITIES XML 1.0 ENTITIES attribute type a white space separated list of ENTITY names
NMTOKEN XML 1.0 NMTOKEN attribute type 12 are you ready
NMTOKENS XML 1.0 NMTOKENS attribute type a white space separated list of name tokens
Name An XML 1.0 Name set, title, rdf, math, math123, href
QName an optionally prefixed, namespace qualified name song:title
NCName a local name without any colons title

Assorted Data Types for Schemas

XML Schema Built-In Simple Types
Name Type Examples
string Parsed Character Data; #PCDATA Hot Cop
normalizedString A string whose normalized value does not contain any tabs, carriage returns, or linefeeds PIC1, PIC2, PIC3, cow_movie, MonaLisa, Hello World , Warhol, red green
token A string whose normalized value has no leading or trailing white space, no tabs, no linefeeds, and not more than one consecutive space p1 p2, ss123 45 6789, _92, red, green, NT Decl, seventeenp1, p2, 123 45 6789, ^*&^*&_92, red green blue, NT-Decl, seventeen; Mary had a little lamb, The love of money is the root of all Evil.
boolean C++'s bool type true, false, 1, 0
anyURI relative or absolute URI http://www.w3.org/TR/2000/WD-xmlschema-2-20000407/#duration, /javafaq/reports/JCE1.2.1.html
hexBinary Arbitrary binary data encoded in hexadecimal form A4E345EC54CC8D52198000FFEA6C
base64Binary Arbitrary binary data encoded in Base64 6jKpNnmkkWeArsn5Oeeg2njcz+nXdk0f9kZI892ddlR8Lg1aMhPeFTYuoq3I6neFlb BjWzuktNZKiXYBfKsSTB8U09dTiJo2ir3HJuY7eW/p89osKMfixPQsp9vQMgzph6Qa lY7j4MB7y5ROJYsTr1/fFwmj/yhkHwpbpzed1LE=

Restricting types


Facets


Length Facets: length, minLength, maxLength


Facets for ordered items: minExclusive, maxExclusive, minInclusive, maxInclusive


Facets for decimal numbers: totalDigits and fractionDigits


Adding a Price

<?xml version="1.0"?>
<SONG>
  <TITLE>Hot Cop</TITLE>
  <COMPOSER>Jacques Morali</COMPOSER>
  <COMPOSER>Henri Belolo</COMPOSER>
  <COMPOSER>Victor Willis</COMPOSER>
  <PRODUCER>Jacques Morali</PRODUCER>
  <PUBLISHER>PolyGram Records</PUBLISHER>
  <YEAR>1978</YEAR>
  <ARTIST>Village People</ARTIST>  
  <PRICE>$1.35</PRICE>  
</SONG>

The pattern facet


Regular Expressions


The Price Schema

<?xml version="1.0"?>
<element name="SONG" xmlns="http://relaxng.org/ns/structure/1.0"
datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
  <element name="TITLE">
    <text/>
  </element>
  <oneOrMore>
    <element name="COMPOSER">
      <data type="string"/>
    </element>
  </oneOrMore>
  <zeroOrMore>
    <element name="PRODUCER">
      <data type="string"/>
    </element>
  </zeroOrMore>
  <optional>
    <element name="PUBLISHER">
      <data type="string"/>
    </element>
  </optional>
  <optional>
    <element name="LENGTH">
      <data type="string"/>
    </element>
  </optional>
  <optional>
    <element name="YEAR">
      <data type="gYear" />
    </element>
  </optional>
  <oneOrMore>
    <element name="ARTIST">
      <data type="string"/>
    </element>
  </oneOrMore>
  <element name="PRICE">
    <data type="string">
      <param name="pattern">\p{Sc}\p{Nd}+(\.\p{Nd}\p{Nd})?</param>
    </data>
  </element>
</element> 

element SONG {
  element TITLE     { text },
  element COMPOSER  { xsd:string }+,
  element PRODUCER  { xsd:string }*,
  element PUBLISHER { xsd:string }?,
  element LENGTH    { xsd:string }?,
  element YEAR      { xsd:gYear }?,
  element ARTIST    { xsd:string }+,
  element PRICE {
    xsd:string { pattern = "\p{Sc}\p{Nd}+(\.\p{Nd}\p{Nd})?" }
  }
}

Lists

Allow multiple years in the YEAR element:

<element name="YEAR">
  <list>
    <oneOrMore>
      <data type="gYear"/>
    </oneOrMore>
  </list>
</element>

element SONG {
  element TITLE     { text },
  element COMPOSER  { xsd:string }+,
  element PRODUCER  { xsd:string }*,
  element PUBLISHER { xsd:string }?,
  element LENGTH    { xsd:string }?,
  element YEAR {
    list { xsd:gYear+ }
  }?,
  element ARTIST    { xsd:string }+
}

User defined type libraries


Prime Datatype

package com.elharo.xml.relaxng;

import org.relaxng.datatype.*;
import org.relaxng.datatype.helpers.StreamingValidatorImpl;

public class PrimeDatatype implements Datatype {

  private boolean isPrime(String literal) {
      
    try {
      int candidate = Integer.parseInt(literal); 
      if (candidate < 2) return false;
      double max = Math.sqrt(candidate);
      for (int i = 2; i <= max; i++) {
        if (candidate % i == 0) return false;
      }
      return true;
    }
    catch (NumberFormatException ex) {
      return false;      
    }
    
  }

  public boolean isValid(String literal, ValidationContext context) {
    return isPrime(literal);
  }

  public void checkValid(String literal, ValidationContext context) 
    throws DatatypeException {

    if (!isValid(literal, context)) {
      throw new DatatypeException(literal + " is not a prime number");
    }
    
  }

  
  public DatatypeStreamingValidator createStreamingValidator(ValidationContext context) {

    // Inefficient but simple. StreamingValidatorImpl stores 
    // everything in a string and then validates the string. More 
    // efficient implementations can validate piece by piece.
    return new StreamingValidatorImpl(this, context);

  }

  
  // These next three methods are closely tied together. The object
  // returned by this method si only used for sameValue and hashCode.
  public Object createValue(String literal, ValidationContext context) {

    if (isPrime(literal)) {
        return Integer.valueOf(literal);
    }
    return null;
    
  }
  
  public boolean sameValue(Object value1, Object value2) {

    if (value1 == null) return value2 == null;
    else return value1.equals(value2);
    
  }

  public int valueHashCode(Object value) {
    return value.hashCode();
  }

  public int getIdType() {
    return ID_TYPE_NULL;
  }

  public boolean isContextDependent() {
    return false;
  }
  
}

Prime Datatype Library

package com.elharo.xml.relaxng;

import org.relaxng.datatype.*;
import org.relaxng.datatype.helpers.*;

public class PrimeDatatypeLibrary implements DatatypeLibrary {

    public Datatype createDatatype(String typeLocalName)
      throws DatatypeException {
        
        if ("prime".equals(typeLocalName)) {
            return new PrimeDatatype();
        }
        throw new DatatypeException("Unsupported type: " + typeLocalName);
        
    }

    public DatatypeBuilder createDatatypeBuilder(String baseTypeLocalName) 
      throws DatatypeException {
        
        return new ParameterlessDatatypeBuilder(
          createDatatype("prime")
        );
        
    }

}

Prime Datatype Library Factory

package com.elharo.xml.relaxng;

import org.relaxng.datatype.*;

public class PrimeDatatypeLibraryFactory implements DatatypeLibraryFactory {

  public final static String namespace 
    = "http://ns.cafeconleche.org/relaxng/primes";

  public DatatypeLibrary createDatatypeLibrary(String namespace) {
  
    if (PrimeDatatypeLibraryFactory.namespace.equals(namespace)) {
      return new PrimeDatatypeLibrary();
    }
    return null;
  
  }

}

Locating type libraries


An invalid document

<?xml version="1.0"?>
<numbers>
  <number>2</number>
  <number>3</number>
  <number>4</number>
  <number>5</number>
  <number>6</number>
</numbers>

A Prime schema

<?xml version="1.0"?>
<element name="numbers" xmlns="http://relaxng.org/ns/structure/1.0">
  <oneOrMore>
    <element name="number">
      <data type="prime"
            datatypeLibrary="http://ns.cafeconleche.org/relaxng/primes"/>
    </element>
  </oneOrMore>
</element>


datatypes d = "http://ns.cafeconleche.org/relaxng/primes"

element numbers {
  element number { d:prime }+
}

include element

<!-- ==============================================================
      SVG12-RNG | SVG 1.2 Full Driver
     ============================================================== -->

<grammar ns='http://www.w3.org/2000/svg' xml:lang='en'
         xmlns='http://relaxng.org/ns/structure/1.0'
         xmlns:xlink='http://www.w3.org/1999/xlink'
         xmlns:a='http://relaxng.org/ns/compatibility/annotations/1.0'
         xmlns:svg='http://www.w3.org/2000/svg'
         datatypeLibrary='http://www.w3.org/2001/XMLSchema-datatypes'>



  <!-- ... common libraries and attributes ........................ -->
  <include href='../Tiny-1.2/datatypes.rng'/>
  <include href='../Tiny-1.2/core-attrib.rng'/>
  <include href='../Tiny-1.2/tiny-paint-attrib.rng'/>
  <include href='../Tiny-1.2/graphics-attrib.rng'/>
  <include href='../Tiny-1.2/transform-attrib.rng'/>
  <include href='../Tiny-1.2/xlink-attrib.rng'/>
  <include href='../Tiny-1.2/extresources-attrib.rng'/>
  <include href='../Tiny-1.2/media-attrib.rng'/>
  <include href='../Tiny-1.2/focusable-attrib.rng'/>
  <include href='../Tiny-1.2/editable-attrib.rng'/>
  <include href='../Tiny-1.2/backgroundfill-attrib.rng'/>
  <include href='opacity-attrib.rng'/>
  <include href='vectoreffects-attrib.rng'/>
  <include href='viewport-attrib.rng'/>


  <!-- ... element definitions .................................... -->
  <include href='structure.rng'/>
  <include href='../Tiny-1.2/conditional.rng'/>
  <include href='../Tiny-1.2/image.rng'/>
  <include href='../Tiny-1.2/shape.rng'/>
  <include href='text.rng'/>
  <include href='../Tiny-1.2/hyperlink.rng'/>
  <include href='../Tiny-1.2/script.rng'/>
  <include href='../Tiny-1.2/animation.rng'/>
  <include href='font.rng'/>
  <include href='../Tiny-1.2/extensibility.rng'/>
  <include href='gradient.rng'/>
  <include href='../Tiny-1.2/solidcolor.rng'/>
  <include href='../Tiny-1.2/audio.rng'/>
  <include href='../Tiny-1.2/video.rng'/>
  <include href='../Tiny-1.2/animation-element.rng'/>
  <include href='../Tiny-1.2/page.rng'/>
  <include href='flow.rng'/>
  <include href='../Tiny-1.2/handler.rng'/>
  <include href='../Tiny-1.2/prefetch.rng'/>

  <!-- ... only available in Full ................................. -->
  <include href='animevents-attrib.rng'/>
  <include href='docevents-attrib.rng'/>
  <include href='graphevents-attrib.rng'/>
  <include href='clip.rng'/>
  <include href='filter.rng'/>
  <include href='mask.rng'/>
  <include href='pattern.rng'/>
  <include href='style.rng'/>
  <include href='transition.rng'/>
  <include href='vectoreffects.rng'/>
  <include href='extendedlink.rng'/>
  <include href='cursor.rng'/>
  <include href='compositing-attrib.rng'/>
  <include href='marker.rng'/>
  <include href='profile.rng'/>
  <include href='shadow-attrib.rng'/>
  <include href='tooltip-attrib.rng'/>
  <include href='view.rng'/>
  <include href='xmlevents.rng'/>
  <include href='multiImage.rng'/>
  <include href='deviceColor.rng'/>
  <include href='traitDef.rng'/>

</grammar>

Compact inclusion syntax

namespace a = "http://relaxng.org/ns/compatibility/annotations/1.0"
namespace svg = "http://www.w3.org/2000/svg"
namespace xlink = "http://www.w3.org/1999/xlink"

# ==============================================================
#  SVG12-RNG | SVG 1.2 Full Driver
# ==============================================================
[ xml:lang = "en" ]
grammar {
  # ... common libraries and attributes ........................
  include "datatypes.rnc" inherit = svg
  include "core-attrib.rnc" inherit = svg
  include "tiny-paint-attrib.rnc" inherit = svg
  include "graphics-attrib.rnc" inherit = svg
  include "transform-attrib.rnc" inherit = svg
  include "xlink-attrib.rnc" inherit = svg
  include "extresources-attrib.rnc" inherit = svg
  include "media-attrib.rnc" inherit = svg
  include "focusable-attrib.rnc" inherit = svg
  include "editable-attrib.rnc" inherit = svg
  include "backgroundfill-attrib.rnc" inherit = svg
  include "opacity-attrib.rnc" inherit = svg
  include "vectoreffects-attrib.rnc" inherit = svg
  include "viewport-attrib.rnc" inherit = svg
  # ... element definitions ....................................
  include "structure.rnc" inherit = svg
  include "conditional.rnc" inherit = svg
  include "image.rnc" inherit = svg
  include "shape.rnc" inherit = svg
  include "text.rnc" inherit = svg
  include "hyperlink.rnc" inherit = svg
  include "script.rnc" inherit = svg
  include "animation.rnc" inherit = svg
  include "font.rnc" inherit = svg
  include "extensibility.rnc" inherit = svg
  include "gradient.rnc" inherit = svg
  include "solidcolor.rnc" inherit = svg
  include "audio.rnc" inherit = svg
  include "video.rnc" inherit = svg
  include "animation-element.rnc" inherit = svg
  include "page.rnc" inherit = svg
  include "flow.rnc" inherit = svg
  include "handler.rnc" inherit = svg
  include "prefetch.rnc" inherit = svg
  # ... only available in Full .................................
  include "animevents-attrib.rnc" inherit = svg
  include "docevents-attrib.rnc" inherit = svg
  include "graphevents-attrib.rnc" inherit = svg
  include "clip.rnc" inherit = svg
  include "filter.rnc" inherit = svg
  include "mask.rnc" inherit = svg
  include "pattern.rnc" inherit = svg
  include "style.rnc" inherit = svg
  include "transition.rnc" inherit = svg
  include "vectoreffects.rnc" inherit = svg
  include "extendedlink.rnc" inherit = svg
  include "cursor.rnc" inherit = svg
  include "compositing-attrib.rnc" inherit = svg
  include "marker.rnc" inherit = svg
  include "profile.rnc" inherit = svg
  include "shadow-attrib.rnc" inherit = svg
  include "tooltip-attrib.rnc" inherit = svg
  include "view.rnc" inherit = svg
  include "xmlevents.rnc" inherit = svg
  include "multiImage.rnc" inherit = svg
  include "deviceColor.rnc" inherit = svg
  include "traitDef.rnc" inherit = svg
}

externalref element

<?xml version="1.0"?>
<SONG>
  <TITLE>Hot Cop</TITLE>
  <COMPOSER>Jacques Morali</COMPOSER>
  <COMPOSER>Henri Belolo</COMPOSER>
  <COMPOSER>Victor Willis</COMPOSER>
  <PRODUCER>Jacques Morali</PRODUCER>
  <PUBLISHER>PolyGram Records</PUBLISHER>
  <LENGTH>6:20</LENGTH>
  <YEAR>1978</YEAR>
  <ARTIST>Village People</ARTIST> 
  <DESCRIPTION>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
      <title>The schema requires this</title>
    </head>
    <body>
    <p>
      A catchy little ditty that never achieved the
      success of <cite>YMCA</cite> or <cite>In the Navy</cite>.
    </p>
    </body>
    </html>
  </DESCRIPTION>
</SONG>

Pointing to the XHTML schema

<?xml version="1.0"?>
<element name="SONG" xmlns="http://relaxng.org/ns/structure/1.0">
  <element name="TITLE">
    <text/>
  </element>
  <oneOrMore>
    <element name="COMPOSER">
      <text/>
    </element>
  </oneOrMore>
  <zeroOrMore>
    <element name="PRODUCER">
      <text/>
    </element>
  </zeroOrMore>
  <optional>
    <element name="PUBLISHER">
      <text/>
    </element>
  </optional>
  <optional>
    <element name="LENGTH">
      <text/>
    </element>
  </optional>
  <optional>
    <element name="YEAR">
      <text/>
    </element>
  </optional>
  <oneOrMore>
    <element name="ARTIST">
      <text/>
    </element>
  </oneOrMore>
  <optional>
    <element name="DESCRIPTION">
      <externalRef href="http://thaiopensource.com/relaxng/xhtml/xhtml-basic.rng"/>
    </element>
  </optional>
</element>

element SONG {
  element TITLE       { text },
  element COMPOSER    { text }+,
  element PRODUCER    { text }*,
  element PUBLISHER   { text }?,
  element LENGTH      { text }?,
  element YEAR        { text }?,
  element ARTIST      { text }+,
  element DESCRIPTION { external "xhtml-basic.rnc" }?
}

Annotations

<?xml version="1.0"?>
<element name="SONG" xmlns="http://relaxng.org/ns/structure/1.0"
datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
  <element name="TITLE">
    <text/>
  </element>
  <interleave>

    <oneOrMore>
      <element name="COMPOSER">
        <data type="string"/>
      </element>
    </oneOrMore>
    <zeroOrMore>
      <element name="PRODUCER">
        <data type="string"/>
      </element>
    </zeroOrMore>
    <oneOrMore>
      <element name="ARTIST">
        <data type="string"/>
      </element>
    </oneOrMore>
  
  <optional>
    <element name="PUBLISHER">
      <data type="string"/>
    </element>
  </optional>
  <optional>
    <element name="LENGTH">
      <data type="string"/>
    </element>
  </optional>
  <optional>
    <element name="YEAR">
      <data type="gYear" />
    </element>
  </optional>

  <element name="PRICE">
    <data type="string">
      <param name="pattern">\p{Sc}\p{Nd}+(\.\p{Nd}\p{Nd})?</param>
    </data>
  </element>
  </interleave>
</element> 

namespace ns1 = "http://www.w3.org/1999/xhtml"

element SONG {
  element TITLE        { text },
  (element COMPOSER    { xsd:string }+
   & element PRODUCER  { xsd:string }*
   & element ARTIST    { xsd:string }+
   & element PUBLISHER { xsd:string }?
   & element LENGTH    { xsd:string }?
   & element YEAR      { xsd:gYear }?
   & element PRICE {
       xsd:string { pattern = "\p{Sc}\p{Nd}+(\.\p{Nd}\p{Nd})?" }
     })
}

RELAX NG in Java 1.5/JAXP 1.3

import javax.xml.*;
import javax.xml.validation.*;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import java.io.*;
import org.xml.sax.*;

public class Relax implements ErrorHandler {

  public static void main(String[] args) {
  
    if (args.length < 2) {
      System.out.println("Usage: java Relax schema.rng file.xml");
      return;
    }
    
    Schema schema;
    try {
      SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.RELAXNG_NS_URI);
      schema = factory.newSchema(new File(args[1]));
    }
    catch (SAXException ex) {
      System.out.println("Schema error in " + args[0]);  
      System.out.println(ex.getMessage());
      return;
    }
    catch (IllegalArgumentException ex) {
      System.out.println("This implementation does not support RELAX NG.");
      return;
    }
    Validator validator = schema.newValidator();
    Source source = new StreamSource(new File(args[1]));
    validator.setErrorHandler(new Relax());
    try {
      validator.validate(source);
    }
    catch (SAXException ex) {
      System.out.println(args[1] + " is not well-formed.");  
      System.out.println(ex.getMessage());
    }
    catch (IOException ex) {
      System.out.println("Could not validate " + args[1] + " due to an I/O error.");  
      System.out.println(ex.getMessage());
    }
    
  }
  
  public void warning(SAXParseException exception) {
    
    System.out.println("Warning: " + exception.getMessage());
    System.out.println(" at line " + exception.getLineNumber() 
     + ", column " + exception.getColumnNumber());
    
  }
  
  public void error(SAXParseException exception) {
     
    System.out.println("Error: " + exception.getMessage());
    System.out.println(" at line " + exception.getLineNumber() 
     + ", column " + exception.getColumnNumber());
    
  }
  
  public void fatalError(SAXParseException exception) {
     
    System.out.println("Fatal Error: " + exception.getMessage());
    System.out.println(" at line " + exception.getLineNumber() 
     + ", column " + exception.getColumnNumber());
     
  }

}

Other features


What RELAX NG doesn't do

* Can be added


RELAX NG is being used for


Trang

$ trang http://www.w3.org/Graphics/SVG/1.2/rng/Full-1.2/Full-1.2.rng full.xsd
http://www.w3.org/Graphics/SVG/1.2/rng/Tiny-1.2/tiny-structure.rng:401:13: warning: choice between attributes and children cannot be represented; approximating
http://www.w3.org/Graphics/SVG/1.2/rng/Tiny-1.2/tiny-structure.rng:420:13: warning: choice between attributes and children cannot be represented; approximating
http://www.w3.org/Graphics/SVG/1.2/rng/Tiny-1.2/tiny-structure.rng:438:13: warning: choice between attributes and children cannot be represented; approximating
http://www.w3.org/Graphics/SVG/1.2/rng/Full-1.2/structure.rng:24:13: warning: choice between attributes and children cannot be represented; approximating
http://www.w3.org/Graphics/SVG/1.2/rng/Tiny-1.2/script.rng:38:13: warning: choice between attributes and children cannot be represented; approximating
http://www.w3.org/Graphics/SVG/1.2/rng/Tiny-1.2/tiny-flow.rng:22:15: warning: cannot represent an optional group of attributes; approximating
http://www.w3.org/Graphics/SVG/1.2/rng/Tiny-1.2/handler.rng:44:13: warning: choice between attributes and children cannot be represented; approximating
http://www.w3.org/Graphics/SVG/1.2/rng/Full-1.2/style.rng:81:13: warning: choice between attributes and children cannot be represented; approximating

To Learn More


Index | Cafe con Leche

Copyright 2005, 2006 Elliotte Rusty Harold
elharo@metalab.unc.edu
Last Modified January 3, 2006