import of the XSD Datatype regression tests from James Clark. Daniel

* check-xsddata-test-suite.py test/xsdtest/xsdtest.xml
  test/xsdtest/xsdtest.xsl: import of the XSD Datatype
  regression tests from James Clark.
Daniel
diff --git a/ChangeLog b/ChangeLog
index f0b78a9..522015d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+Thu Feb 27 21:09:32 CET 2003 Daniel Veillard <daniel@veillard.com>
+
+	* check-xsddata-test-suite.py test/xsdtest/xsdtest.xml
+	  test/xsdtest/xsdtest.xsl: import of the XSD Datatype
+	  regression tests from James Clark.
+
 Thu Feb 27 18:40:04 CET 2003 Daniel Veillard <daniel@veillard.com>
 
 	* relaxng.c xmlschemas.c xmlschemastypes.c
diff --git a/check-xsddata-test-suite.py b/check-xsddata-test-suite.py
new file mode 100755
index 0000000..b0c63e1
--- /dev/null
+++ b/check-xsddata-test-suite.py
@@ -0,0 +1,369 @@
+#!/usr/bin/python
+import sys
+import time
+import os
+import string
+import StringIO
+sys.path.append("python")
+import libxml2
+
+# Memory debug specific
+libxml2.debugMemory(1)
+debug = 0
+
+#
+# the testsuite description
+#
+CONF="test/xsdtest/xsdtestsuite.xml"
+LOG="check-xsdtype-test-suite.log"
+
+log = open(LOG, "w")
+nb_schemas_tests = 0
+nb_schemas_success = 0
+nb_schemas_failed = 0
+nb_instances_tests = 0
+nb_instances_success = 0
+nb_instances_failed = 0
+
+libxml2.lineNumbersDefault(1)
+#
+# Error and warnng callbacks
+#
+def callback(ctx, str):
+    global log
+    log.write("%s%s" % (ctx, str))
+
+libxml2.registerErrorHandler(callback, "")
+
+#
+# Resolver callback
+#
+resources = {}
+def resolver(URL, ID, ctxt):
+    global resources
+
+    if resources.has_key(URL):
+        return(StringIO.StringIO(resources[URL]))
+    log.write("Resolver failure: asked %s\n" % (URL))
+    log.write("resources: %s\n" % (resources))
+    return None
+
+#
+# handle a valid instance
+#
+def handle_valid(node, schema):
+    global log
+    global nb_instances_success
+    global nb_instances_failed
+
+    instance = ""
+    child = node.children
+    while child != None:
+        if child.type != 'text':
+	    instance = instance + child.serialize()
+	child = child.next
+
+    try:
+	doc = libxml2.parseDoc(instance)
+    except:
+        doc = None
+
+    if doc == None:
+        log.write("\nFailed to parse correct instance:\n-----\n")
+	log.write(instance)
+        log.write("\n-----\n")
+	nb_instances_failed = nb_instances_failed + 1
+	return
+
+    try:
+        ctxt = schema.relaxNGNewValidCtxt()
+	ret = doc.relaxNGValidateDoc(ctxt)
+    except:
+        ret = -1
+    if ret != 0:
+        log.write("\nFailed to validate correct instance:\n-----\n")
+	log.write(instance)
+        log.write("\n-----\n")
+	nb_instances_failed = nb_instances_failed + 1
+    else:
+	nb_instances_success = nb_instances_success + 1
+    doc.freeDoc()
+
+#
+# handle an invalid instance
+#
+def handle_invalid(node, schema):
+    global log
+    global nb_instances_success
+    global nb_instances_failed
+
+    instance = ""
+    child = node.children
+    while child != None:
+        if child.type != 'text':
+	    instance = instance + child.serialize()
+	child = child.next
+
+    try:
+	doc = libxml2.parseDoc(instance)
+    except:
+        doc = None
+
+    if doc == None:
+        log.write("\nStrange: failed to parse incorrect instance:\n-----\n")
+	log.write(instance)
+        log.write("\n-----\n")
+	return
+
+    try:
+        ctxt = schema.relaxNGNewValidCtxt()
+	ret = doc.relaxNGValidateDoc(ctxt)
+    except:
+        ret = -1
+    if ret == 0:
+        log.write("\nFailed to detect validation problem in instance:\n-----\n")
+	log.write(instance)
+        log.write("\n-----\n")
+	nb_instances_failed = nb_instances_failed + 1
+    else:
+	nb_instances_success = nb_instances_success + 1
+    doc.freeDoc()
+
+#
+# handle an incorrect test
+#
+def handle_correct(node):
+    global log
+    global nb_schemas_success
+    global nb_schemas_failed
+
+    schema = ""
+    child = node.children
+    while child != None:
+        if child.type != 'text':
+	    schema = schema + child.serialize()
+	child = child.next
+
+    try:
+	rngp = libxml2.relaxNGNewMemParserCtxt(schema, len(schema))
+	rngs = rngp.relaxNGParse()
+    except:
+        rngs = None
+    if rngs == None:
+        log.write("\nFailed to compile correct schema:\n-----\n")
+	log.write(schema)
+        log.write("\n-----\n")
+	nb_schemas_failed = nb_schemas_failed + 1
+    else:
+	nb_schemas_success = nb_schemas_success + 1
+    return rngs
+        
+def handle_incorrect(node):
+    global log
+    global nb_schemas_success
+    global nb_schemas_failed
+
+    schema = ""
+    child = node.children
+    while child != None:
+        if child.type != 'text':
+	    schema = schema + child.serialize()
+	child = child.next
+
+    try:
+	rngp = libxml2.relaxNGNewMemParserCtxt(schema, len(schema))
+	rngs = rngp.relaxNGParse()
+    except:
+        rngs = None
+    if rngs != None:
+        log.write("\nFailed to detect schema error in:\n-----\n")
+	log.write(schema)
+        log.write("\n-----\n")
+	nb_schemas_failed = nb_schemas_failed + 1
+    else:
+#	log.write("\nSuccess detecting schema error in:\n-----\n")
+#	log.write(schema)
+#	log.write("\n-----\n")
+	nb_schemas_success = nb_schemas_success + 1
+    return None
+
+#
+# resource handling: keep a dictionary of URL->string mappings
+#
+def handle_resource(node, dir):
+    global resources
+
+    try:
+	name = node.prop('name')
+    except:
+        name = None
+
+    if name == None or name == '':
+        log.write("resource has no name")
+	return;
+        
+    if dir != None:
+#        name = libxml2.buildURI(name, dir)
+        name = dir + '/' + name
+
+    res = ""
+    child = node.children
+    while child != None:
+        if child.type != 'text':
+	    res = res + child.serialize()
+	child = child.next
+    resources[name] = res
+
+#
+# dir handling: pseudo directory resources
+#
+def handle_dir(node, dir):
+    try:
+	name = node.prop('name')
+    except:
+        name = None
+
+    if name == None or name == '':
+        log.write("resource has no name")
+	return;
+        
+    if dir != None:
+#        name = libxml2.buildURI(name, dir)
+        name = dir + '/' + name
+
+    dirs = node.xpathEval('dir')
+    for dir in dirs:
+        handle_dir(dir, name)
+    res = node.xpathEval('resource')
+    for r in res:
+        handle_resource(r, name)
+
+#
+# handle a testCase element
+#
+def handle_testCase(node):
+    global nb_schemas_tests
+    global nb_instances_tests
+    global resources
+
+    sections = node.xpathEval('string(section)')
+    log.write("\n    ======== test %d line %d section %s ==========\n" % (
+
+              nb_schemas_tests, node.lineNo(), sections))
+    resources = {}
+    if debug:
+        print "test %d line %d" % (nb_schemas_tests, node.lineNo())
+
+    dirs = node.xpathEval('dir')
+    for dir in dirs:
+        handle_dir(dir, None)
+    res = node.xpathEval('resource')
+    for r in res:
+        handle_resource(r, None)
+
+    tsts = node.xpathEval('incorrect')
+    if tsts != []:
+        if len(tsts) != 1:
+	    print "warning test line %d has more than one <incorrect> example" %(node.lineNo())
+	schema = handle_incorrect(tsts[0])
+    else:
+        tsts = node.xpathEval('correct')
+	if tsts != []:
+	    if len(tsts) != 1:
+		print "warning test line %d has more than one <correct> example"% (node.lineNo())
+	    schema = handle_correct(tsts[0])
+	else:
+	    print "warning <testCase> line %d has no <correct> nor <incorrect> child" % (node.lineNo())
+
+    nb_schemas_tests = nb_schemas_tests + 1;
+    
+    valids = node.xpathEval('valid')
+    invalids = node.xpathEval('invalid')
+    nb_instances_tests = nb_instances_tests + len(valids) + len(invalids)
+    if schema != None:
+        for valid in valids:
+	    handle_valid(valid, schema)
+        for invalid in invalids:
+	    handle_invalid(invalid, schema)
+
+
+#
+# handle a testSuite element
+#
+def handle_testSuite(node, level = 0):
+    global nb_schemas_tests, nb_schemas_success, nb_schemas_failed
+    global nb_instances_tests, nb_instances_success, nb_instances_failed
+    if level >= 1:
+	old_schemas_tests = nb_schemas_tests
+	old_schemas_success = nb_schemas_success
+	old_schemas_failed = nb_schemas_failed
+	old_instances_tests = nb_instances_tests
+	old_instances_success = nb_instances_success
+	old_instances_failed = nb_instances_failed
+
+    docs = node.xpathEval('documentation')
+    authors = node.xpathEval('author')
+    if docs != []:
+        msg = ""
+        for doc in docs:
+	    msg = msg + doc.content + " "
+	if authors != []:
+	    msg = msg + "written by "
+	    for author in authors:
+	        msg = msg + author.content + " "
+	print msg
+    sections = node.xpathEval('section')
+    if sections != [] and level <= 0:
+        msg = ""
+        for section in sections:
+	    msg = msg + section.content + " "
+        print "Tests for section %s" % (msg)
+    for test in node.xpathEval('testCase'):
+        handle_testCase(test)
+    for test in node.xpathEval('testSuite'):
+        handle_testSuite(test, level + 1)
+	        
+
+    if level >= 1 and sections != []:
+        msg = ""
+        for section in sections:
+	    msg = msg + section.content + " "
+        print "Result of tests for section %s" % (msg)
+        if nb_schemas_tests != old_schemas_tests:
+	    print "found %d test schemas: %d success %d failures" % (
+		  nb_schemas_tests - old_schemas_tests,
+		  nb_schemas_success - old_schemas_success,
+		  nb_schemas_failed - old_schemas_failed)
+	if nb_instances_tests != old_instances_tests:
+	    print "found %d test instances: %d success %d failures" % (
+		  nb_instances_tests - old_instances_tests,
+		  nb_instances_success - old_instances_success,
+		  nb_instances_failed - old_instances_failed)
+#
+# Parse the conf file
+#
+libxml2.substituteEntitiesDefault(1);
+testsuite = libxml2.parseFile(CONF)
+libxml2.setEntityLoader(resolver)
+root = testsuite.getRootElement()
+if root.name != 'testSuite':
+    print "%s doesn't start with a testSuite element, aborting" % (CONF)
+    sys.exit(1)
+print "Running Relax NG testsuite"
+handle_testSuite(root)
+
+print "\nTOTAL:\nfound %d test schemas: %d success %d failures" % (
+      nb_schemas_tests, nb_schemas_success, nb_schemas_failed)
+print "found %d test instances: %d success %d failures" % (
+      nb_instances_tests, nb_instances_success, nb_instances_failed)
+
+testsuite.freeDoc()
+
+# Memory debug specific
+libxml2.relaxNGCleanupTypes()
+libxml2.cleanupParser()
+if libxml2.debugMemory(1) == 0:
+    print "OK"
+else:
+    print "Memory leak %d bytes" % (libxml2.debugMemory(1))
+    libxml2.dumpMemory()
diff --git a/test/xsdtest/xsdtest.xml b/test/xsdtest/xsdtest.xml
new file mode 100644
index 0000000..2fe94b6
--- /dev/null
+++ b/test/xsdtest/xsdtest.xml
@@ -0,0 +1,805 @@
+<xsdtest>
+<datatype name="dateTime">
+<valid>2001-12-01T19:45:00</valid>
+<valid>2001-12-01T19:45:00Z</valid>
+<valid>2001-12-01T19:45:00-11:59</valid>
+<valid>0001-01-12T00:00:00+12:00</valid>
+<invalid>2001-12-1T19:45:00+24:00</invalid>
+<invalid>2001-12-1T19:45:00</invalid>
+<equiv>
+<class>
+  <value>2001-12-01T19:45:00</value>
+  <value>2001-12-01T19:45:00.00</value>
+</class>
+<class>
+  <value>2001-12-01T19:45:00Z</value>
+  <value>2001-12-01T19:45:00.00Z</value>
+  <value>2001-12-01T20:45:00+01:00</value>
+</class>
+</equiv>
+</datatype>
+<datatype name="anyURI">
+<valid>foobar</valid>
+<valid>http://www.example.com</valid>
+<valid>http://www.example.co%6d</valid>
+<valid>nosuchscheme:stuff</valid>
+<invalid>foo$bar:stuff</invalid>
+<invalid>f%oobar</invalid>
+</datatype>
+<datatype name="integer">
+<valid>10</valid>
+<valid>01</valid>
+<valid>0123456789</valid>
+<valid>+10</valid>
+<valid>-10</valid>
+<invalid>1.0</invalid>
+<invalid>.1</invalid>
+<valid>9999999999999999999999999999999</valid>
+<invalid>1.</invalid>
+<invalid>0.</invalid>
+<equiv>
+<class>
+  <value>0</value>
+  <value>+0</value>
+  <value>-0</value>
+  <value>00</value>
+</class>
+<class>
+  <value>10</value>
+  <value>+10</value>
+  <value>+0010</value>
+  <value>010</value>
+</class>
+<class>
+  <value>-10</value>
+  <value>-0010</value>
+  <value>-010</value>
+</class>
+</equiv>
+</datatype>
+<datatype name="duration">
+<valid>P1Y</valid>
+<valid>P1Y0M2DT17H5M12S</valid>
+<valid>-P1Y</valid>
+<valid>P60D</valid>
+<valid>PT24H</valid>
+<valid>PT1.2S</valid>
+<invalid>P24h</invalid>
+<invalid>P24H</invalid>
+<invalid>P1YT</invalid>
+<invalid>P</invalid>
+<invalid>-P</invalid>
+<equiv>
+  <class>
+    <value>-P6M</value>
+  </class>
+  <class>
+    <value>P0Y</value>
+    <value>-P0Y</value>
+  </class>
+  <class>
+    <value>P1Y</value>
+    <value>P001Y</value>
+    <value>P001Y0M</value>
+    <value>P1Y0M0DT0H0M0.0S</value>
+  </class>
+  <class>
+    <value>P6M</value>
+  </class>
+  <class>
+    <value>PT6M</value>
+  </class>
+  <class>
+    <value>PT1S</value>
+    <value>PT1.0S</value>
+  </class>
+</equiv>
+<lessThan>
+  <value>PT1M</value>
+  <value>PT61S</value>
+</lessThan>
+<lessThan>
+  <value>PT59S</value>
+  <value>PT1M</value>
+</lessThan>
+<incomparable>
+  <value>PT60S</value>
+  <value>PT1M</value>
+</incomparable>
+<lessThan>
+  <value>PT1H</value>
+  <value>PT61M</value>
+</lessThan>
+<lessThan>
+  <value>PT59M</value>
+  <value>PT1H</value>
+</lessThan>
+<incomparable>
+  <value>PT60M</value>
+  <value>PT1H</value>
+</incomparable>
+<lessThan>
+  <value>P1D</value>
+  <value>PT25H</value>
+</lessThan>
+<lessThan>
+  <value>PT23H</value>
+  <value>P1D</value>
+</lessThan>
+<incomparable>
+  <value>P1D</value>
+  <value>PT24H</value>
+</incomparable>
+<lessThan>
+  <value>P1Y</value>
+  <value>P13M</value>
+</lessThan>
+<lessThan>
+  <value>P11M</value>
+  <value>P1Y</value>
+</lessThan>
+<incomparable>
+  <value>P12M</value>
+  <value>P1Y</value>
+</incomparable>
+<lessThan>
+  <value>P364D</value>
+  <value>P1Y</value>
+</lessThan>
+<incomparable>
+  <value>P1Y</value>
+  <value>P365D</value>
+</incomparable>
+<incomparable>
+  <value>P1Y</value>
+  <value>P366D</value>
+</incomparable>
+<lessThan>
+  <value>P1Y</value>
+  <value>P367D</value>
+</lessThan>
+<lessThan>
+  <value>P149D</value>
+  <value>P5M</value>
+</lessThan>
+<incomparable>
+  <value>P150D</value>
+  <value>P5M</value>
+</incomparable>
+<incomparable>
+  <value>P151D</value>
+  <value>P5M</value>
+</incomparable>
+<incomparable>
+  <value>P152D</value>
+  <value>P5M</value>
+</incomparable>
+<incomparable>
+  <value>P153D</value>
+  <value>P5M</value>
+</incomparable>
+<lessThan>
+  <value>P5M</value>
+  <value>P154D</value>
+</lessThan>
+<lessThan>
+  <value>P27D</value>
+  <value>P1M</value>
+</lessThan>
+<incomparable>
+  <value>P28D</value>
+  <value>P1M</value>
+</incomparable>
+<incomparable>
+  <value>P29D</value>
+  <value>P1M</value>
+</incomparable>
+<incomparable>
+  <value>P30D</value>
+  <value>P1M</value>
+</incomparable>
+<incomparable>
+  <value>P31D</value>
+  <value>P1M</value>
+</incomparable>
+<lessThan>
+  <value>P1M</value>
+  <value>P32D</value>
+</lessThan>
+</datatype>
+<datatype name="time">
+<valid>12:45:00</valid>
+<valid>12:45:00Z</valid>
+</datatype>
+<datatype name="date">
+<valid>1886-12-01</valid>
+<valid>1886-12-01Z</valid>
+<lessThan>
+  <value>1066-12-31</value>
+  <value>1900-01-01</value>
+</lessThan>
+<lessThan>
+  <value>1900-01-01</value>
+  <value>1900-01-02</value>
+</lessThan>
+</datatype>
+<datatype name="gYearMonth">
+<valid>1996-12</valid>
+<valid>1996-01</valid>
+<valid>1996-01Z</valid>
+<invalid>1996-00</invalid>
+<equiv>
+<class><value>1996-01</value></class>
+<class>
+  <value>1996-01Z</value>
+  <value>1996-01+00:00</value>
+  <value>1996-01-00:00</value>
+</class>
+<class><value>1996-01+01:00</value></class>
+<class><value>1996-01-01:00</value></class>
+</equiv>
+</datatype>
+<datatype name="gYear">
+<valid>2001</valid>
+<valid>2001Z</valid>
+<lessThan>
+  <value>1999</value>
+  <value>2000</value>
+</lessThan>
+<lessThan>
+  <value>1999+07:00</value>
+  <value>2000+07:00</value>
+</lessThan>
+</datatype>
+<datatype name="gMonthDay">
+<valid>--12-01</valid>
+<valid>--12-01Z</valid>
+<lessThan>
+  <value>--12-01</value>
+  <value>--12-04</value>
+</lessThan>
+<lessThan>
+  <value>--11-17</value>
+  <value>--12-04</value>
+</lessThan>
+</datatype>
+<datatype name="gDay">
+<valid>---20</valid>
+<valid>---20Z</valid>
+<lessThan>
+  <value>---01</value>
+  <value>---31</value>
+</lessThan>
+</datatype>
+<datatype name="gMonth">
+<valid>--12</valid>
+<valid>--01</valid>
+<valid>--01Z</valid>
+<valid> --12 </valid>
+<invalid>---01</invalid>
+<invalid>--00</invalid>
+<invalid>--13</invalid>
+<invalid>- -13</invalid>
+<lessThan>
+  <value>--01</value>
+  <value>--12</value>
+</lessThan>
+<lessThan>
+  <value>--01</value>
+  <value>--02</value>
+</lessThan>
+</datatype>
+<datatype name="boolean">
+<valid>true</valid>
+<valid>false</valid>
+<valid>0</valid>
+<valid>1</valid>
+<invalid>00</invalid>
+<invalid>00</invalid>
+<invalid>01</invalid>
+<equiv>
+<class><value>true</value><value>1</value></class>
+<class><value>false</value><value>0</value></class>
+</equiv>
+</datatype>
+<datatype name="base64Binary">
+<valid>AAAA</valid>
+<valid>abcd efgh ijkl mnop qrst uvwx yzAB CDEF GHIJ KLMN OPQR
+STUV WXYZ 0123 4567 89+/</valid>
+<valid>BA==</valid>
+<valid></valid>
+<valid>BA==</valid>
+<valid>BQ==</valid>
+<valid>Bg==</valid>
+<valid>Bw==</valid>
+<valid>BBA=</valid>
+<valid>BBA=</valid>
+<valid>BBE=</valid>
+<valid>BBI=</valid>
+<valid>BBM=</valid>
+<valid>BBQ=</valid>
+<valid>BBU=</valid>
+<valid>BBY=</valid>
+<valid>BBc=</valid>
+<valid>BBg=</valid>
+<valid>BBk=</valid>
+<valid>BBo=</valid>
+<valid>BBs=</valid>
+<valid>BBw=</valid>
+<valid>BB0=</valid>
+<valid>BB4=</valid>
+<valid>BB8=</valid>
+<invalid>====</invalid>
+<invalid>BB==</invalid>
+<invalid>BBB=</invalid>
+<invalid>B===</invalid>
+<invalid>B</invalid>
+<equiv>
+<class>
+<value>deadbeef</value>
+<value>d&#xA;&#xD;&#x9;e a d
+b eef </value>
+</class>
+<class>
+<value>DEADBEEF</value>
+<value>D&#xA;&#xD;&#x9;E A D
+B EEF </value>
+</class>
+</equiv>
+<length value="0"></length>
+<length value="6">deadbeef</length>
+<length value="1">BA==</length>
+<length value="2">BBA=</length>
+<length value="3">dead</length>
+<length value="4">deadBA==</length>
+</datatype>
+<datatype name="hexBinary">
+<valid>deadbeef</valid>
+<valid></valid>
+<valid>0123456789ABCDEFabcdef</valid>
+<invalid>00 00</invalid>
+<invalid>00.00</invalid>
+<invalid>0G</invalid>
+<equiv>
+ <class>
+   <value>00</value>
+   <value>
+	00
+   </value>
+ </class>
+ <class>
+   <value>01</value>
+ </class>
+ <class>
+   <value>10</value>
+ </class>
+ <class>
+   <value>0a</value>
+   <value>0A</value>
+ </class>
+</equiv>
+<length value="0"></length>
+<length value="1">00</length>
+<length value="2">0000</length>
+<length value="2"> 0000 </length>
+<length value="2">AAAA</length>
+</datatype>
+<datatype name="float">
+<valid>1.0</valid>
+<valid>1.</valid>
+<valid>.1</valid>
+<invalid>- 1</invalid>
+<invalid>1 .0</invalid>
+<invalid>+INF</invalid>
+<invalid>+NaN</invalid>
+<invalid>-NaN</invalid>
+<equiv>
+<class>
+  <value>0</value>
+  <value>-0</value>
+  <value>+0</value>
+  <value> 0 </value>
+  <value> 0. </value>
+  <value> .0 </value>
+  <value> 0.0 </value>
+  <value> 0e0 </value>
+  <value> 0E0 </value>
+  <value> 0E+0 </value>
+  <value> 0E-0 </value>
+</class>
+<class>
+  <value>1E0</value>
+  <value>0.1E1</value>
+  <value>10E-1</value>
+  <value>+1</value>
+</class>
+<class>
+  <value>-1</value>
+</class>
+<class>
+  <value>INF</value>
+  <value>INF </value>
+</class>
+<class>
+  <value>-INF</value>
+  <value>-INF </value>
+</class>
+<class>
+  <value>NaN</value>
+  <value> NaN </value>
+</class>
+</equiv>
+<lessThan>
+  <value>-INF</value>
+  <value>-1000</value>
+</lessThan>
+<lessThan>
+  <value>1000</value>
+  <value>INF</value>
+</lessThan>
+<lessThan>
+  <value>-1</value>
+  <value>1</value>
+</lessThan>
+<lessThan>
+  <value>0</value>
+  <value>1</value>
+</lessThan>
+<lessThan>
+  <value>-1</value>
+  <value>0</value>
+</lessThan>
+</datatype>
+<datatype name="double">
+<valid>1.0</valid>
+<valid>1.</valid>
+<valid>.1</valid>
+<invalid>- 1</invalid>
+<invalid>1 .0</invalid>
+<invalid>+INF</invalid>
+<invalid>+NaN</invalid>
+<invalid>-NaN</invalid>
+<equiv>
+<class>
+  <value>0</value>
+  <value>-0</value>
+  <value>+0</value>
+  <value> 0 </value>
+  <value> 0. </value>
+  <value> .0 </value>
+  <value> 0.0 </value>
+  <value> 0e0 </value>
+  <value> 0E0 </value>
+  <value> 0E+0 </value>
+  <value> 0E-0 </value>
+</class>
+<class>
+  <value>1E0</value>
+  <value>0.1E1</value>
+  <value>10E-1</value>
+  <value>+1</value>
+</class>
+<class>
+  <value>-1</value>
+</class>
+<class>
+  <value>INF</value>
+  <value>INF </value>
+</class>
+<class>
+  <value>-INF</value>
+  <value>-INF </value>
+</class>
+<class>
+  <value>NaN</value>
+  <value> NaN </value>
+</class>
+</equiv>
+<lessThan>
+  <value>-INF</value>
+  <value>-1000</value>
+</lessThan>
+<lessThan>
+  <value>1000</value>
+  <value>INF</value>
+</lessThan>
+<lessThan>
+  <value>-1</value>
+  <value>1</value>
+</lessThan>
+<lessThan>
+  <value>0</value>
+  <value>1</value>
+</lessThan>
+<lessThan>
+  <value>-1</value>
+  <value>0</value>
+</lessThan>
+</datatype>
+<datatype name="QName">
+<valid>foo</valid>
+<valid xmlns:x="http://www.example.com">x:foo</valid>
+<invalid>y:foo</invalid>
+<equiv xmlns:x="http://www.example.com"
+       xmlns:y="http://www.example.com/"
+       xmlns:z="http://www.example.com">
+<class>
+  <value>foo</value>
+  <value> foo</value>
+</class>
+<class>
+  <value>x:foo</value>
+  <value> x:foo </value>
+  <value>z:foo</value>
+</class>
+<class>
+  <value>x:bar</value>
+  <value>z:bar</value>
+</class>
+<class>
+  <value>y:foo</value>
+</class>
+<class>
+  <value>y:bar</value>
+</class>
+</equiv>
+</datatype>
+<datatype name="NOTATION">
+<valid>foo</valid>
+<valid xmlns:x="http://www.example.com">x:foo</valid>
+<invalid>y:foo</invalid>
+</datatype>
+<datatype name="decimal">
+<valid>1.0</valid>
+<valid>1.</valid>
+<valid>.1</valid>
+<valid>+1.0</valid>
+<valid>-1.0</valid>
+<valid> 1 </valid>
+<valid>99999999999999999999999999999999999999999999999999999999999999999</valid>
+<valid>-99999999999999999999999999999999999999999999999999999999999999999</valid>
+<invalid>junk</invalid>
+<invalid>--1</invalid>
+<invalid>++1</invalid>
+<invalid>+-1</invalid>
+<invalid>1.2.</invalid>
+<invalid>..1</invalid>
+<invalid>1..</invalid>
+<invalid>1 .2</invalid>
+<invalid>1+</invalid>
+<invalid>+ 1</invalid>
+<lessThan>
+  <value>0</value>
+  <value>1</value>
+</lessThan>
+</datatype>
+<datatype name="nonPositiveInteger">
+<valid>-1</valid>
+<valid>0</valid>
+<valid>-0</valid>
+<invalid>1</invalid>
+</datatype>
+<datatype name="nonNegativeInteger">
+<valid>1</valid>
+<valid>0</valid>
+<valid>+1</valid>
+<valid>+0</valid>
+<invalid>-1</invalid>
+</datatype>
+<datatype name="positiveInteger">
+<valid>+1</valid>
+<valid>1</valid>
+<invalid>0</invalid>
+<invalid>-1</invalid>
+</datatype>
+<datatype name="negativeInteger">
+<valid>-1</valid>
+<invalid>+1</invalid>
+<invalid>0</invalid>
+</datatype>
+<datatype name="long">
+<valid>1</valid>
+<valid>+1</valid>
+<valid>0</valid>
+<valid> 0 </valid>
+<invalid>1 2</invalid>
+<invalid>9999999999999999999999999999999999999999999999999999999999999999999999999</invalid>
+<valid>9223372036854775807</valid>
+<valid>-9223372036854775808</valid>
+<invalid>9223372036854775808</invalid>
+<invalid>-9223372036854775809</invalid>
+<invalid/>
+</datatype>
+<datatype name="int">
+<valid>1</valid>
+<valid>01</valid>
+<valid> 1 </valid>
+<valid>2147483647</valid>
+<valid>-2147483648</valid>
+<invalid>2147483648</invalid>
+<invalid>-2147483649</invalid>
+<invalid>9999999999999999999999999999999999999999999999999999999999999999999999999</invalid>
+<equiv>
+<class>
+ <value>1</value>
+ <value>+1</value>
+ <value> 1 </value>
+ <value>001</value>
+</class>
+<class>
+ <value>-1</value>
+ <value> -1 </value>
+ <value>-001</value>
+</class>
+</equiv>
+</datatype>
+<datatype name="short">
+<valid>1</valid>
+<valid>32767</valid>
+<valid>-32768</valid>
+<invalid>32768</invalid>
+<invalid>-32769</invalid>
+<invalid>9999999999999999999999999999999999999999999999999999999999999999999999999</invalid>
+<equiv>
+<class>
+ <value>1</value>
+ <value>+1</value>
+ <value> 1 </value>
+ <value>001</value>
+</class>
+<class>
+ <value>-1</value>
+ <value> -1 </value>
+ <value>-001</value>
+</class>
+</equiv>
+</datatype>
+<datatype name="byte">
+<valid>1</valid>
+<valid>127</valid>
+<valid>-128</valid>
+<invalid>128</invalid>
+<invalid>-129</invalid>
+</datatype>
+<datatype name="unsignedLong">
+<valid>1</valid>
+<valid>+1</valid>
+<invalid>-1</invalid>
+<valid>0</valid>
+<valid>18446744073709551615</valid>
+<invalid>18446744073709551616</invalid>
+<invalid>-1</invalid>
+</datatype>
+<datatype name="unsignedInt">
+<valid>1</valid>
+<valid>+1</valid>
+<valid>0</valid>
+<valid>4294967295</valid>
+<invalid>4294967296</invalid>
+<invalid>-1</invalid>
+</datatype>
+<datatype name="unsignedShort">
+<valid>1</valid>
+<valid>+1</valid>
+<valid>0</valid>
+<valid>65535</valid>
+<invalid>65536</invalid>
+<invalid>-1</invalid>
+</datatype>
+<datatype name="unsignedByte">
+<valid>1</valid>
+<valid>+1</valid>
+<valid>0</valid>
+<valid>255</valid>
+<invalid>256</invalid>
+<invalid>-1</invalid>
+</datatype>
+<datatype name="string">
+<valid>any thing at all!</valid>
+</datatype>
+<datatype name="normalizedString">
+<valid>any thing at all!</valid>
+</datatype>
+<datatype name="token">
+<valid>any thing at all!</valid>
+<equiv>
+<class>
+  <value/>
+  <value> </value>
+  <value>&#x9;&#xA;&#xD;&#x20;</value>
+</class>
+<class>
+  <value>x&#x20;</value>
+  <value>x&#xA;</value>
+  <value>x&#xD;</value>
+  <value>x&#x9;</value>
+  <value>&#x20;x</value>
+  <value>&#xA;x</value>
+  <value>&#xD;x</value>
+  <value>&#x9;x</value>
+  <value>&#x9;&#xA;&#xD;&#x20;x&#x9;&#xA;&#xD;&#x20;</value>
+</class>
+<class>
+  <value>x y&#x20;</value>
+  <value>x y&#xA;</value>
+  <value>x y&#xD;</value>
+  <value>x y&#x9;</value>
+  <value>x&#x20;y</value>
+  <value>x&#xA;y</value>
+  <value>x&#xD;y</value>
+  <value>x&#x9;y</value>
+  <value>&#x20;x y</value>
+  <value>&#xA;x y</value>
+  <value>&#xD;x y</value>
+  <value>&#x9;x y</value>
+  <value>&#x9;&#xA;&#xD;&#x20;x&#x9;&#xA;&#xD;&#x20;y&#x9;&#xA;&#xD;&#x20;</value>
+</class>
+</equiv>
+<length value="0"></length>
+<length value="1">x</length>
+<length value="1"> x </length>
+<length value="1">&#x10800;</length>
+</datatype>
+<datatype name="language">
+<valid>en</valid>
+<valid>en-UK</valid>
+<valid>i-cherokee</valid>
+<valid>x-klingon</valid>
+<valid>en-uk-scotland</valid>
+<invalid>en.UK</invalid>
+</datatype>
+<datatype name="Name">
+<valid>foo</valid>
+<valid>_0123456789</valid>
+<invalid>.</invalid>
+<valid>:</valid>
+<invalid>-</invalid>
+<invalid>1234</invalid>
+<valid> foo </valid>
+</datatype>
+<datatype name="NCName">
+<valid>foo</valid>
+<invalid>foo:bar</invalid>
+<invalid>0foo</invalid>
+<equiv>
+<class><value>foo</value><value> foo </value></class>
+<class><value>FOO</value><value> FOO </value></class>
+</equiv>
+</datatype>
+<datatype name="NMTOKEN">
+<valid>foo</valid>
+<valid>_</valid>
+<valid>.</valid>
+<valid>:</valid>
+<valid>-</valid>
+<valid>1234</valid>
+<valid> foo </valid>
+<length value="3"> foo </length>
+<length value="2">fo</length>
+<length value="1">f</length>
+</datatype>
+<datatype name="NMTOKENS">
+<valid>foo bar</valid>
+<invalid/>
+<valid>1 2 3 4</valid>
+</datatype>
+<datatype name="ID">
+<valid>foobar</valid>
+<invalid>foo:bar</invalid>
+<invalid>foo bar</invalid>
+</datatype>
+<datatype name="ENTITY">
+<invalid/>
+<invalid>foo</invalid>
+<valid internalSubset="&lt;!ENTITY foo SYSTEM 'whatever' NDATA jpeg>"
+>foo</valid>
+</datatype>
+<datatype name="ENTITIES">
+<invalid></invalid>
+<invalid>foo</invalid>
+<valid internalSubset="&lt;!ENTITY foo SYSTEM 'whatever' NDATA jpeg>
+&#xA;&lt;!ENTITY bar SYSTEM 'whatever' NDATA jpeg>
+"
+> foo bar </valid>
+</datatype>
+</xsdtest>
diff --git a/test/xsdtest/xsdtest.xsl b/test/xsdtest/xsdtest.xsl
new file mode 100644
index 0000000..1290b16
--- /dev/null
+++ b/test/xsdtest/xsdtest.xsl
@@ -0,0 +1,235 @@
+<?xml version="1.0"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+<xsl:strip-space elements="xsdtest datatype equiv class"/>
+
+<xsl:output indent="yes" encoding="utf-8"/>
+
+<xsl:template match="xsdtest">
+  <testSuite>
+    <xsl:apply-templates/>
+  </testSuite>
+</xsl:template>
+
+<xsl:template match="datatype">
+<testCase>
+<requires datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"/>
+<correct>
+<element xmlns="http://relaxng.org/ns/structure/1.0" name="doc"
+         datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+  <data type="{@name}">
+    <xsl:for-each select="param">
+      <param name="{@name}"><xsl:value-of select="."/></param>
+    </xsl:for-each>
+  </data>
+</element>
+</correct>
+<xsl:apply-templates select="valid|invalid"/>
+</testCase>
+<xsl:apply-templates select="equiv/class|length|lessThan|incomparable"/>
+</xsl:template>
+
+<xsl:template match="valid">
+ <xsl:call-template name="valid"/>
+</xsl:template>
+
+<xsl:template match="invalid">
+ <xsl:call-template name="invalid"/>
+</xsl:template>
+
+<xsl:template name="valid">
+  <valid>
+    <xsl:apply-templates select="@internalSubset"/>
+    <doc>
+      <xsl:copy-of select="namespace::*"/>
+      <xsl:value-of select="."/>
+    </doc>
+  </valid>
+</xsl:template>
+
+<xsl:template name="invalid">
+  <invalid>
+    <xsl:apply-templates select="@internalSubset"/>
+    <doc>
+      <xsl:copy-of select="namespace::*"/>
+      <xsl:value-of select="."/>
+    </doc>
+  </invalid>
+</xsl:template>
+
+<xsl:template match="@internalSubset">
+  <xsl:param name="doc" select="'doc'"/>
+  <xsl:attribute name="dtd">
+    <xsl:text>
+&lt;!DOCTYPE </xsl:text>
+    <xsl:value-of select="$doc"/>
+    <xsl:text> [
+</xsl:text>
+    <xsl:value-of select="."/>
+    <xsl:text>
+]></xsl:text>
+  </xsl:attribute>
+</xsl:template>
+
+<xsl:template match="class">
+<testCase>
+<correct>
+  <xsl:for-each select="value[1]">
+    <xsl:apply-templates select="@internalSubset">
+      <xsl:with-param name="doc">element</xsl:with-param>
+    </xsl:apply-templates>
+    <element xmlns="http://relaxng.org/ns/structure/1.0" name="doc"
+         datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+      <value>
+        <xsl:copy-of select="namespace::*"/>
+        <xsl:attribute name="type"><xsl:value-of select="../../../@name"/></xsl:attribute>
+        <xsl:value-of select="."/>
+      </value>
+    </element>
+  </xsl:for-each>
+</correct>
+<xsl:for-each select="value[position() != 1]">
+  <xsl:call-template name="valid"/>
+</xsl:for-each>
+<xsl:for-each select="preceding-sibling::class/value|following-sibling::class/value">
+  <xsl:call-template name="invalid"/>
+</xsl:for-each>
+</testCase>
+</xsl:template>
+
+<xsl:template match="length">
+<testCase>
+<correct>
+<element xmlns="http://relaxng.org/ns/structure/1.0" name="doc"
+         datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+  <data type="{../@name}">
+    <param name="length"><xsl:value-of select="@value"/></param>
+  </data>
+</element>
+</correct>
+<xsl:call-template name="valid"/>
+</testCase>
+
+<testCase>
+<correct>
+<element xmlns="http://relaxng.org/ns/structure/1.0" name="doc"
+         datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+  <data type="{../@name}">
+    <param name="length"><xsl:value-of select="@value + 1"/></param>
+  </data>
+</element>
+</correct>
+<xsl:call-template name="invalid"/>
+</testCase>
+
+<xsl:if test="@value != 0">
+  <testCase>
+  <correct>
+  <element xmlns="http://relaxng.org/ns/structure/1.0" name="doc"
+	   datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+    <data type="{../@name}">
+      <param name="length"><xsl:value-of select="@value - 1"/></param>
+    </data>
+  </element>
+  </correct>
+  <xsl:call-template name="invalid"/>
+  </testCase>
+</xsl:if>
+
+</xsl:template>
+
+<xsl:template match="lessThan">
+<testCase>
+<correct>
+  <element xmlns="http://relaxng.org/ns/structure/1.0" name="doc"
+	   datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+    <data type="{../@name}">
+      <param name="minExclusive">
+        <xsl:value-of select="value[1]"/>
+      </param>
+    </data>
+   </element>
+</correct>
+<valid>
+<doc>
+<xsl:value-of select="value[2]"/>
+</doc>
+</valid>
+<invalid>
+<doc>
+<xsl:value-of select="value[1]"/>
+</doc>
+</invalid>
+</testCase>
+<testCase>
+<correct>
+  <element xmlns="http://relaxng.org/ns/structure/1.0" name="doc"
+	   datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+    <data type="{../@name}">
+      <param name="minExclusive">
+        <xsl:value-of select="value[2]"/>
+      </param>
+    </data>
+   </element>
+</correct>
+<invalid>
+<doc>
+<xsl:value-of select="value[1]"/>
+</doc>
+</invalid>
+<invalid>
+<doc>
+<xsl:value-of select="value[2]"/>
+</doc>
+</invalid>
+</testCase>
+</xsl:template>
+
+<xsl:template match="incomparable">
+<testCase>
+<correct>
+  <element xmlns="http://relaxng.org/ns/structure/1.0" name="doc"
+	   datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+    <data type="{../@name}">
+      <param name="minExclusive">
+        <xsl:value-of select="value[1]"/>
+      </param>
+    </data>
+   </element>
+</correct>
+<invalid>
+<doc>
+<xsl:value-of select="value[2]"/>
+</doc>
+</invalid>
+<invalid>
+<doc>
+<xsl:value-of select="value[1]"/>
+</doc>
+</invalid>
+</testCase>
+<testCase>
+<correct>
+  <element xmlns="http://relaxng.org/ns/structure/1.0" name="doc"
+	   datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+    <data type="{../@name}">
+      <param name="minExclusive">
+        <xsl:value-of select="value[2]"/>
+      </param>
+    </data>
+   </element>
+</correct>
+<invalid>
+<doc>
+<xsl:value-of select="value[1]"/>
+</doc>
+</invalid>
+<invalid>
+<doc>
+<xsl:value-of select="value[2]"/>
+</doc>
+</invalid>
+</testCase>
+</xsl:template>
+
+</xsl:stylesheet>