changed xmlPatterncompile signature to pass an int and not an enum since

* pattern.c include/libxml/pattern.h: changed xmlPatterncompile
  signature to pass an int and not an enum since it can generate
  ABI compat troubles.
* include/libxml/schematron.h schematron.c: adding the new
  schematron code, work in progress lots to be left and needing
  testing
* include/libxml/xmlversion.h.in include/libxml/xmlwin32version.h.in
  Makefile.am configure.in: integration of schematron into the
  build
* xpath.c include/libxml/xpath.h: adding flags to control compilation
  options right now just XML_XPATH_CHECKNS.
Daniel
diff --git a/ChangeLog b/ChangeLog
index 7922c15..27435f6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+Sat Jul 23 10:55:50 EDT 2005 Daniel Veillard <daniel@veillard.com>
+
+	* pattern.c include/libxml/pattern.h: changed xmlPatterncompile
+	  signature to pass an int and not an enum since it can generate
+	  ABI compat troubles.
+	* include/libxml/schematron.h schematron.c: adding the new 
+	  schematron code, work in progress lots to be left and needing
+	  testing
+	* include/libxml/xmlversion.h.in include/libxml/xmlwin32version.h.in
+	  Makefile.am configure.in: integration of schematron into the
+	  build
+	* xpath.c include/libxml/xpath.h: adding flags to control compilation
+	  options right now just XML_XPATH_CHECKNS.
+
 Sat Jul 23 16:39:35 CEST 2005 Kasimier Buchcik <libxml2-cvs@cazic.net>
 
 	* xmlschemas.c: Removed an "internal error" message from
diff --git a/Makefile.am b/Makefile.am
index 69dba11..1485e51 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -27,7 +27,8 @@
 		catalog.c globals.c threads.c c14n.c xmlstring.c \
 		xmlregexp.c xmlschemas.c xmlschemastypes.c xmlunicode.c \
 		triostr.c trio.c xmlreader.c relaxng.c dict.c SAX2.c \
-		xmlwriter.c legacy.c chvalid.c pattern.c xmlsave.c xmlmodule.c
+		xmlwriter.c legacy.c chvalid.c pattern.c xmlsave.c \
+		xmlmodule.c schematron.c
 else
 libxml2_la_SOURCES = SAX.c entities.c encoding.c error.c parserInternals.c  \
 		parser.c tree.c hash.c list.c xmlIO.c xmlmemory.c uri.c  \
@@ -37,7 +38,7 @@
 		xmlregexp.c xmlschemas.c xmlschemastypes.c xmlunicode.c \
 		xmlreader.c relaxng.c dict.c SAX2.c \
 		xmlwriter.c legacy.c chvalid.c pattern.c xmlsave.c \
-		xmlmodule.c
+		xmlmodule.c schematron.c
 endif
 
 DEPS = $(top_builddir)/libxml2.la
diff --git a/configure.in b/configure.in
index 7cc51c2..9b16c4c 100644
--- a/configure.in
+++ b/configure.in
@@ -128,6 +128,8 @@
 [  --with-sax1             add the older SAX1 interface (on)])
 AC_ARG_WITH(schemas,
 [  --with-schemas          add Relax-NG and Schemas support (on)])
+AC_ARG_WITH(schematron,
+[  --with-schematron       add Schematron support (on)])
 AC_ARG_WITH(threads,
 [  --with-threads          add multithread support(on)])
 AC_ARG_WITH(thread-alloc,
@@ -163,6 +165,11 @@
     with_pattern=yes
     with_regexp=yes
 fi
+if test "$with_schematron" = "yes"
+then
+    with_pattern=yes
+    with_xpath=yes
+fi
 if test "$with_reader" = "yes"
 then
     with_push=yes
@@ -270,6 +277,10 @@
     then
       with_schemas=no
     fi
+    if test "$with_schematron" = ""
+    then
+      with_schematron=no
+    fi
     if test "$with_threads" = ""
     then
       with_threads=no
@@ -1152,6 +1163,20 @@
 fi
 AC_SUBST(WITH_ISO8859X)
 
+if test "$with_schematron" = "no" ; then
+    echo "Disabling Schematron support"
+    WITH_SCHEMATRON=0
+    TEST_SCHEMATRON=
+else    
+    echo "Enabled Schematron support"
+    WITH_SCHEMATRON=1
+    TEST_SCHEMATRON="Schematrontests"
+    with_xpath=yes
+    with_pattern=yes
+fi
+AC_SUBST(WITH_SCHEMATRON)
+AC_SUBST(TEST_SCHEMATRON)
+
 if test "$with_schemas" = "no" ; then
     echo "Disabling Schemas/Relax-NG support"
     WITH_SCHEMAS=0
diff --git a/include/libxml/pattern.h b/include/libxml/pattern.h
index e3ee76d..c058bd9 100644
--- a/include/libxml/pattern.h
+++ b/include/libxml/pattern.h
@@ -52,7 +52,7 @@
 XMLPUBFUN xmlPatternPtr XMLCALL
 			xmlPatterncompile	(const xmlChar *pattern,
 						 xmlDict *dict,
-						 xmlPatternFlags flags,
+						 int flags,
 						 const xmlChar **namespaces);
 XMLPUBFUN int XMLCALL
 			xmlPatternMatch		(xmlPatternPtr comp,
diff --git a/include/libxml/schematron.h b/include/libxml/schematron.h
new file mode 100644
index 0000000..a1a809a
--- /dev/null
+++ b/include/libxml/schematron.h
@@ -0,0 +1,126 @@
+/*
+ * Summary: XML Schemastron implementation
+ * Description: interface to the XML Schematron validity checking.
+ *
+ * Copy: See Copyright for the status of this software.
+ *
+ * Author: Daniel Veillard
+ */
+
+
+#ifndef __XML_SCHEMATRON_H__
+#define __XML_SCHEMATRON_H__
+
+#include <libxml/xmlversion.h>
+
+#ifdef LIBXML_SCHEMATRON_ENABLED
+
+#include <libxml/tree.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define XML_SCHEMATRON_NS BAD_CAST "http://purl.oclc.org/dsdl/schematron"
+
+typedef enum {
+    XML_SCHEMATRON_OUT_QUIET = 1 << 0,	/* quiet no report */
+    XML_SCHEMATRON_OUT_TEXT = 1 << 1,	/* build a textual report */
+    XML_SCHEMATRON_OUT_XML = 1 << 2,	/* output SVRL */
+    XML_SCHEMATRON_OUT_FILE = 1 << 8,	/* output to a file descriptor */
+    XML_SCHEMATRON_OUT_BUFFER = 1 << 9,	/* output to a buffer */
+    XML_SCHEMATRON_OUT_IO = 1 << 10	/* output to I/O mechanism */
+} xmlSchematronValidOptions;
+
+/**
+ * The schemas related types are kept internal
+ */
+typedef struct _xmlSchematron xmlSchematron;
+typedef xmlSchematron *xmlSchematronPtr;
+
+/**
+ * A schemas validation context
+ */
+typedef void (*xmlSchematronValidityErrorFunc) (void *ctx, const char *msg, ...);
+typedef void (*xmlSchematronValidityWarningFunc) (void *ctx, const char *msg, ...);
+
+typedef struct _xmlSchematronParserCtxt xmlSchematronParserCtxt;
+typedef xmlSchematronParserCtxt *xmlSchematronParserCtxtPtr;
+
+typedef struct _xmlSchematronValidCtxt xmlSchematronValidCtxt;
+typedef xmlSchematronValidCtxt *xmlSchematronValidCtxtPtr;
+
+/*
+ * Interfaces for parsing.
+ */
+XMLPUBFUN xmlSchematronParserCtxtPtr XMLCALL 
+	    xmlSchematronNewParserCtxt	(const char *URL);
+XMLPUBFUN xmlSchematronParserCtxtPtr XMLCALL 
+	    xmlSchematronNewMemParserCtxt(const char *buffer,
+					 int size);
+XMLPUBFUN xmlSchematronParserCtxtPtr XMLCALL
+	    xmlSchematronNewDocParserCtxt(xmlDocPtr doc);
+XMLPUBFUN void XMLCALL		
+	    xmlSchematronFreeParserCtxt	(xmlSchematronParserCtxtPtr ctxt);
+XMLPUBFUN void XMLCALL		
+	    xmlSchematronSetParserErrors(xmlSchematronParserCtxtPtr ctxt,
+					 xmlSchematronValidityErrorFunc err,
+					 xmlSchematronValidityWarningFunc warn,
+					 void *ctx);
+XMLPUBFUN int XMLCALL
+		xmlSchematronGetParserErrors(xmlSchematronParserCtxtPtr ctxt,
+					xmlSchematronValidityErrorFunc * err,
+					xmlSchematronValidityWarningFunc * warn,
+					void **ctx);
+XMLPUBFUN int XMLCALL
+		xmlSchematronIsValid	(xmlSchematronValidCtxtPtr ctxt);
+
+XMLPUBFUN xmlSchematronPtr XMLCALL	
+	    xmlSchematronParse		(xmlSchematronParserCtxtPtr ctxt);
+XMLPUBFUN void XMLCALL		
+	    xmlSchematronFree		(xmlSchematronPtr schema);
+#ifdef LIBXML_OUTPUT_ENABLED
+XMLPUBFUN void XMLCALL		
+	    xmlSchematronDump		(FILE *output,
+					 xmlSchematronPtr schema);
+#endif /* LIBXML_OUTPUT_ENABLED */
+/*
+ * Interfaces for validating
+ */
+XMLPUBFUN void XMLCALL		
+	    xmlSchematronSetValidErrors	(xmlSchematronValidCtxtPtr ctxt,
+					 xmlSchematronValidityErrorFunc err,
+					 xmlSchematronValidityWarningFunc warn,
+					 void *ctx);
+XMLPUBFUN void XMLCALL
+	    xmlSchematronSetValidStructuredErrors(xmlSchematronValidCtxtPtr ctxt,
+								  xmlStructuredErrorFunc serror, void *ctx);
+XMLPUBFUN int XMLCALL
+	    xmlSchematronGetValidErrors	(xmlSchematronValidCtxtPtr ctxt,
+					 xmlSchematronValidityErrorFunc *err,
+					 xmlSchematronValidityWarningFunc *warn,
+					 void **ctx);
+XMLPUBFUN int XMLCALL
+	    xmlSchematronSetValidOptions(xmlSchematronValidCtxtPtr ctxt,
+					 int options);
+XMLPUBFUN int XMLCALL
+	    xmlSchematronValidCtxtGetOptions(xmlSchematronValidCtxtPtr ctxt);
+
+XMLPUBFUN xmlSchematronValidCtxtPtr XMLCALL	
+	    xmlSchematronNewValidCtxt	(xmlSchematronPtr schema,
+	    				 int options);
+XMLPUBFUN void XMLCALL			
+	    xmlSchematronFreeValidCtxt	(xmlSchematronValidCtxtPtr ctxt);
+XMLPUBFUN int XMLCALL			
+	    xmlSchematronValidateDoc	(xmlSchematronValidCtxtPtr ctxt,
+					 xmlDocPtr instance);
+XMLPUBFUN int XMLCALL
+            xmlSchematronValidateOneElement (xmlSchematronValidCtxtPtr ctxt,
+			                 xmlNodePtr elem);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBXML_SCHEMATRON_ENABLED */
+#endif /* __XML_SCHEMATRON_H__ */
diff --git a/include/libxml/xmlversion.h.in b/include/libxml/xmlversion.h.in
index 47a28b9..f97aa35 100644
--- a/include/libxml/xmlversion.h.in
+++ b/include/libxml/xmlversion.h.in
@@ -340,6 +340,15 @@
 #endif
 
 /**
+ * LIBXML_SCHEMATRON_ENABLED:
+ *
+ * Whether the Schematron validation interfaces are compiled in
+ */
+#if @WITH_SCHEMATRON@
+#define LIBXML_SCHEMATRON_ENABLED
+#endif
+
+/**
  * LIBXML_MODULES_ENABLED:
  *
  * Whether the module interfaces are compiled in
diff --git a/include/libxml/xmlwin32version.h.in b/include/libxml/xmlwin32version.h.in
index 24e3471..544d5a9 100644
--- a/include/libxml/xmlwin32version.h.in
+++ b/include/libxml/xmlwin32version.h.in
@@ -166,6 +166,15 @@
 #endif
 
 /**
+ * LIBXML_SCHEMATRON_ENABLED:
+ *
+ * Whether the Schematron validation interfaces are compiled in
+ */
+#if 1
+#define LIBXML_SCHEMATRON_ENABLED
+#endif
+
+/**
  * LIBXML_ICONV_ENABLED:
  *
  * Whether iconv support is available
diff --git a/include/libxml/xpath.h b/include/libxml/xpath.h
index eee2630..6b2bfa3 100644
--- a/include/libxml/xpath.h
+++ b/include/libxml/xpath.h
@@ -249,6 +249,14 @@
 					 const xmlChar *ns_uri);
 
 /**
+ * xmlXPathFlags:
+ * Flags for XPath engine compilation and runtime
+ */
+typedef enum {
+    XML_XPATH_CHECKNS = 1		/* check namespaces at compilation */
+} xmlXPathFlags;
+
+/**
  * xmlXPathContext:
  *
  * Expression evaluation occurs with respect to a context.
@@ -324,6 +332,8 @@
 
     /* dictionnary */
     xmlDictPtr dict;			/* dictionnary if any */
+
+    int flags;				/* flags to control compilation */
 };
 
 /*
diff --git a/pattern.c b/pattern.c
index 2749230..e76fef5 100644
--- a/pattern.c
+++ b/pattern.c
@@ -1954,7 +1954,7 @@
  * xmlPatterncompile:
  * @pattern: the pattern to compile
  * @dict: an optional dictionary for interned strings
- * @flags: compilation flags, undefined yet
+ * @flags: compilation flags, see xmlPatternFlags
  * @namespaces: the prefix definitions, array of [URI, prefix] or NULL
  *
  * Compile a pattern.
@@ -1962,8 +1962,7 @@
  * Returns the compiled form of the pattern or NULL in case of error
  */
 xmlPatternPtr
-xmlPatterncompile(const xmlChar *pattern, xmlDict *dict,
-                  xmlPatternFlags flags,
+xmlPatterncompile(const xmlChar *pattern, xmlDict *dict, int flags,
                   const xmlChar **namespaces) {
     xmlPatternPtr ret = NULL, cur;
     xmlPatParserContextPtr ctxt = NULL;
diff --git a/schematron.c b/schematron.c
new file mode 100644
index 0000000..4211b78
--- /dev/null
+++ b/schematron.c
@@ -0,0 +1,1316 @@
+/*
+ * schemas.c : implementation of the Schematron schema validity checking
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel Veillard <veillard@redhat.com>
+ */
+
+#define IN_LIBXML
+#include "libxml.h"
+
+#ifdef LIBXML_SCHEMATRON_ENABLED
+
+#include <string.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/uri.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+#include <libxml/pattern.h>
+#include <libxml/schematron.h>
+
+#define SCHEMATRON_PARSE_OPTIONS XML_PARSE_NOENT
+
+static const xmlChar *xmlSchematronNs = XML_SCHEMATRON_NS;
+
+#define IS_SCHEMATRON(node, elem)					\
+   ((node != NULL) && (node->type == XML_ELEMENT_NODE ) &&		\
+    (node->ns != NULL) &&						\
+    (xmlStrEqual(node->name, (const xmlChar *) elem)) &&		\
+    (xmlStrEqual(node->ns->href, xmlSchematronNs)))
+
+#define NEXT_SCHEMATRON(node)						\
+   while (node != NULL) {						\
+       if ((node->type == XML_ELEMENT_NODE ) && (node->ns != NULL) && 	\
+           (xmlStrEqual(node->ns->href, xmlSchematronNs)))		\
+	   break;							\
+       node = node->next;						\
+   }
+
+/**
+ * TODO:
+ *
+ * macro to flag unimplemented blocks
+ */
+#define TODO 								\
+    xmlGenericError(xmlGenericErrorContext,				\
+	    "Unimplemented block at %s:%d\n",				\
+            __FILE__, __LINE__);
+
+#define XML_SCHEMATRON_ASSERT 0
+#define XML_SCHEMATRON_REPORT 1
+/**
+ * _xmlSchematronTest:
+ *
+ * A Schematrons test, either an assert or a report
+ */
+typedef struct _xmlSchematronTest xmlSchematronTest;
+typedef xmlSchematronTest *xmlSchematronTestPtr;
+struct _xmlSchematronTest {
+    xmlSchematronTestPtr next;	/* the next test in the list */
+    int type;			/* 0 for assert, 1 for report */
+    xmlNodePtr node;		/* the node in the tree */
+    xmlChar *test;		/* the expression to test */
+    xmlXPathCompExprPtr comp;	/* the compiled expression */
+};
+
+/**
+ * _xmlSchematronRule:
+ *
+ * A Schematrons rule
+ */
+typedef struct _xmlSchematronRule xmlSchematronRule;
+typedef xmlSchematronRule *xmlSchematronRulePtr;
+struct _xmlSchematronRule {
+    xmlSchematronRulePtr next;	/* the next rule in the list */
+    xmlNodePtr node;		/* the node in the tree */
+    xmlChar *context;		/* the context evaluation rule */
+    xmlSchematronTestPtr tests;	/* the list of tests */
+    xmlPatternPtr pattern;	/* the compiled pattern associated */
+};
+
+/**
+ * _xmlSchematron:
+ *
+ * A Schematrons definition
+ */
+struct _xmlSchematron {
+    const xmlChar *name;	/* schema name */
+    int preserve;		/* was the document preserved by the user */
+    xmlDocPtr doc;		/* pointer to the parsed document */
+    int flags;			/* specific to this schematron */
+
+    void *_private;		/* unused by the library */
+    xmlDictPtr dict;		/* the dictionnary used internally */
+
+    const xmlChar *title;	/* the title if any */
+
+    int nbNs;			/* the number of namespaces */
+
+    int nbPattern;		/* the number of patterns */
+    xmlSchematronRulePtr rules;	/* the rules gathered */
+    int nbNamespaces;		/* number of namespaces in the array */
+    int maxNamespaces;		/* size of the array */
+    const xmlChar **namespaces;	/* the array of namespaces */
+};
+
+/**
+ * xmlSchematronValidCtxt:
+ *
+ * A Schematrons validation context
+ */
+struct _xmlSchematronValidCtxt {
+    int type;
+    int flags;			/* an or of xmlSchematronValidOptions */
+
+    xmlDictPtr dict;
+    int nberrors;
+    int err;
+
+    xmlSchematronPtr schema;
+    xmlXPathContextPtr xctxt;
+
+    FILE *outputFile;		/* if using XML_SCHEMATRON_OUT_FILE */
+    xmlBufferPtr outputBuffer;	/* if using XML_SCHEMATRON_OUT_BUFFER */
+    xmlOutputWriteCallback iowrite; /* if using XML_SCHEMATRON_OUT_IO */
+    xmlOutputCloseCallback  ioclose;
+    void *ioctx;
+};
+
+struct _xmlSchematronParserCtxt {
+    int type;
+    const xmlChar *URL;
+    xmlDocPtr doc;
+    int preserve;               /* Whether the doc should be freed  */
+    const char *buffer;
+    int size;
+
+    xmlDictPtr dict;            /* dictionnary for interned string names */
+
+    int nberrors;
+    int err;
+    xmlXPathContextPtr xctxt;	/* the XPath context used for compilation */
+    xmlSchematronPtr schema;
+
+    int nbNamespaces;		/* number of namespaces in the array */
+    int maxNamespaces;		/* size of the array */
+    const xmlChar **namespaces;	/* the array of namespaces */
+
+    int nbIncludes;		/* number of includes in the array */
+    int maxIncludes;		/* size of the array */
+    xmlNodePtr *includes;	/* the array of includes */
+
+    /* error rreporting data */
+    void *userData;                      /* user specific data block */
+    xmlSchematronValidityErrorFunc error;/* the callback in case of errors */
+    xmlSchematronValidityWarningFunc warning;/* callback in case of warning */
+    xmlStructuredErrorFunc serror;       /* the structured function */
+
+};
+
+#define XML_STRON_CTXT_PARSER 1
+#define XML_STRON_CTXT_VALIDATOR 2
+
+/************************************************************************
+ *									*
+ *			Error reporting					*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlSchematronPErrMemory:
+ * @node: a context node
+ * @extra:  extra informations
+ *
+ * Handle an out of memory condition
+ */
+static void
+xmlSchematronPErrMemory(xmlSchematronParserCtxtPtr ctxt,
+                        const char *extra, xmlNodePtr node)
+{
+    if (ctxt != NULL)
+        ctxt->nberrors++;
+    __xmlSimpleError(XML_FROM_SCHEMASP, XML_ERR_NO_MEMORY, node, NULL,
+                     extra);
+}
+
+/**
+ * xmlSchematronPErr:
+ * @ctxt: the parsing context
+ * @node: the context node
+ * @error: the error code
+ * @msg: the error message
+ * @str1: extra data
+ * @str2: extra data
+ * 
+ * Handle a parser error
+ */
+static void
+xmlSchematronPErr(xmlSchematronParserCtxtPtr ctxt, xmlNodePtr node, int error,
+              const char *msg, const xmlChar * str1, const xmlChar * str2)
+{
+    xmlGenericErrorFunc channel = NULL;
+    xmlStructuredErrorFunc schannel = NULL;
+    void *data = NULL;
+
+    if (ctxt != NULL) {
+        ctxt->nberrors++;
+        channel = ctxt->error;
+        data = ctxt->userData;
+	schannel = ctxt->serror;
+    }
+    __xmlRaiseError(schannel, channel, data, ctxt, node, XML_FROM_SCHEMASP,
+                    error, XML_ERR_ERROR, NULL, 0,
+                    (const char *) str1, (const char *) str2, NULL, 0, 0,
+                    msg, str1, str2);
+}
+
+/**
+ * xmlSchematronVTypeErrMemory:
+ * @node: a context node
+ * @extra:  extra informations
+ *
+ * Handle an out of memory condition
+ */
+static void
+xmlSchematronVErrMemory(xmlSchematronValidCtxtPtr ctxt,
+                        const char *extra, xmlNodePtr node)
+{
+    if (ctxt != NULL) {
+        ctxt->nberrors++;
+        ctxt->err = XML_SCHEMAV_INTERNAL;
+    }
+    __xmlSimpleError(XML_FROM_SCHEMASV, XML_ERR_NO_MEMORY, node, NULL,
+                     extra);
+}
+
+/************************************************************************
+ *									*
+ *		Parsing and compilation of the Schematrontrons		*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlSchematronAddTest:
+ * @ctxt: the schema parsing context
+ * @schema:  a schema structure
+ * @node:  the node hosting the test
+ * @context: the associated context string
+ *
+ * Add a test to a schematron
+ *
+ * Returns the new pointer or NULL in case of error
+ */
+static xmlSchematronTestPtr
+xmlSchematronAddTest(xmlSchematronParserCtxtPtr ctxt, int type,
+                     xmlSchematronRulePtr rule,
+                     xmlNodePtr node, xmlChar *test)
+{
+    xmlSchematronTestPtr ret;
+    xmlXPathCompExprPtr comp;
+
+    if ((ctxt == NULL) || (rule == NULL) || (node == NULL) ||
+        (test == NULL))
+        return(NULL);
+
+    /*
+     * try first to compile the test expression
+     */
+    comp = xmlXPathCtxtCompile(ctxt->xctxt, test);
+    if (comp == NULL) {
+	xmlSchematronPErr(ctxt, node,
+	    XML_SCHEMAP_NOROOT,
+	    "Failed to compile test expression %s",
+	    test, NULL);
+	return(NULL);
+    }
+
+    ret = (xmlSchematronTestPtr) xmlMalloc(sizeof(xmlSchematronTest));
+    if (ret == NULL) {
+        xmlSchematronPErrMemory(ctxt, "allocating schema test", node);
+        return (NULL);
+    }
+    memset(ret, 0, sizeof(xmlSchematronTest));
+    ret->type = type;
+    ret->node = node;
+    ret->test = test;
+    ret->comp = comp;
+    ret->next = rule->tests;
+    rule->tests = ret;
+    return (ret);
+}
+
+/**
+ * xmlSchematronFreeTests:
+ * @tests:  a list of tests
+ *
+ * Free a list of tests.
+ */
+static void
+xmlSchematronFreeTests(xmlSchematronTestPtr tests) {
+    xmlSchematronTestPtr next;
+
+    while (tests != NULL) {
+        next = tests->next;
+	if (tests->test != NULL)
+	    xmlFree(tests->test);
+	if (tests->comp != NULL)
+	    xmlXPathFreeCompExpr(tests->comp);
+	xmlFree(tests);
+	tests = next;
+    }
+}
+
+/**
+ * xmlSchematronAddRule:
+ * @ctxt: the schema parsing context
+ * @schema:  a schema structure
+ * @node:  the node hosting the rule
+ * @context: the associated context string
+ *
+ * Add a rule to a schematron
+ *
+ * Returns the new pointer or NULL in case of error
+ */
+static xmlSchematronRulePtr
+xmlSchematronAddRule(xmlSchematronParserCtxtPtr ctxt, xmlSchematronPtr schema,
+                     xmlNodePtr node, xmlChar *context)
+{
+    xmlSchematronRulePtr ret;
+    xmlPatternPtr pattern;
+
+    if ((ctxt == NULL) || (schema == NULL) || (node == NULL) ||
+        (context == NULL))
+        return(NULL);
+
+    /*
+     * Try first to compile the pattern
+     */
+    pattern = xmlPatterncompile(context, ctxt->dict, XML_PATTERN_XPATH,
+                                ctxt->namespaces);
+    if (pattern == NULL) {
+	xmlSchematronPErr(ctxt, node,
+	    XML_SCHEMAP_NOROOT,
+	    "Failed to compile context expression %s",
+	    context, NULL);
+    }
+
+    ret = (xmlSchematronRulePtr) xmlMalloc(sizeof(xmlSchematronRule));
+    if (ret == NULL) {
+        xmlSchematronPErrMemory(ctxt, "allocating schema rule", node);
+        return (NULL);
+    }
+    memset(ret, 0, sizeof(xmlSchematronRule));
+    ret->node = node;
+    ret->context = context;
+    ret->next = schema->rules;
+    ret->pattern = pattern;
+    schema->rules = ret;
+    return (ret);
+}
+
+/**
+ * xmlSchematronFreeRules:
+ * @rules:  a list of rules
+ *
+ * Free a list of rules.
+ */
+static void
+xmlSchematronFreeRules(xmlSchematronRulePtr rules) {
+    xmlSchematronRulePtr next;
+
+    while (rules != NULL) {
+        next = rules->next;
+	if (rules->tests)
+	    xmlSchematronFreeTests(rules->tests);
+	if (rules->context != NULL)
+	    xmlFree(rules->context);
+	if (rules->pattern)
+	    xmlFreePattern(rules->pattern);
+	xmlFree(rules);
+	rules = next;
+    }
+}
+
+/**
+ * xmlSchematronNewSchematron:
+ * @ctxt:  a schema validation context
+ *
+ * Allocate a new Schematron structure.
+ *
+ * Returns the newly allocated structure or NULL in case or error
+ */
+static xmlSchematronPtr
+xmlSchematronNewSchematron(xmlSchematronParserCtxtPtr ctxt)
+{
+    xmlSchematronPtr ret;
+
+    ret = (xmlSchematronPtr) xmlMalloc(sizeof(xmlSchematron));
+    if (ret == NULL) {
+        xmlSchematronPErrMemory(ctxt, "allocating schema", NULL);
+        return (NULL);
+    }
+    memset(ret, 0, sizeof(xmlSchematron));
+    ret->dict = ctxt->dict;
+    xmlDictReference(ret->dict);
+
+    return (ret);
+}
+
+/**
+ * xmlSchematronFree:
+ * @schema:  a schema structure
+ *
+ * Deallocate a Schematron structure.
+ */
+void
+xmlSchematronFree(xmlSchematronPtr schema)
+{
+    if (schema == NULL)
+        return;
+
+    if ((schema->doc != NULL) && (!(schema->preserve)))
+        xmlFreeDoc(schema->doc);
+
+    if (schema->namespaces != NULL)
+        xmlFree(schema->namespaces);
+    
+    xmlSchematronFreeRules(schema->rules);
+    xmlDictFree(schema->dict);
+    xmlFree(schema);
+}
+
+/**
+ * xmlSchematronNewParserCtxt:
+ * @URL:  the location of the schema
+ *
+ * Create an XML Schematrons parse context for that file/resource expected
+ * to contain an XML Schematrons file.
+ *
+ * Returns the parser context or NULL in case of error
+ */
+xmlSchematronParserCtxtPtr
+xmlSchematronNewParserCtxt(const char *URL)
+{
+    xmlSchematronParserCtxtPtr ret;
+
+    if (URL == NULL)
+        return (NULL);
+
+    ret =
+        (xmlSchematronParserCtxtPtr)
+        xmlMalloc(sizeof(xmlSchematronParserCtxt));
+    if (ret == NULL) {
+        xmlSchematronPErrMemory(NULL, "allocating schema parser context",
+                                NULL);
+        return (NULL);
+    }
+    memset(ret, 0, sizeof(xmlSchematronParserCtxt));
+    ret->type = XML_STRON_CTXT_PARSER;
+    ret->dict = xmlDictCreate();
+    ret->URL = xmlDictLookup(ret->dict, (const xmlChar *) URL, -1);
+    ret->includes = 0;
+    ret->xctxt = xmlXPathNewContext(NULL);
+    if (ret->xctxt == NULL) {
+        xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context",
+                                NULL);
+	xmlSchematronFreeParserCtxt(ret);
+        return (NULL);
+    }
+    ret->xctxt->flags = XML_XPATH_CHECKNS;
+    return (ret);
+}
+
+/**
+ * xmlSchematronNewMemParserCtxt:
+ * @buffer:  a pointer to a char array containing the schemas
+ * @size:  the size of the array
+ *
+ * Create an XML Schematrons parse context for that memory buffer expected
+ * to contain an XML Schematrons file.
+ *
+ * Returns the parser context or NULL in case of error
+ */
+xmlSchematronParserCtxtPtr
+xmlSchematronNewMemParserCtxt(const char *buffer, int size)
+{
+    xmlSchematronParserCtxtPtr ret;
+
+    if ((buffer == NULL) || (size <= 0))
+        return (NULL);
+
+    ret =
+        (xmlSchematronParserCtxtPtr)
+        xmlMalloc(sizeof(xmlSchematronParserCtxt));
+    if (ret == NULL) {
+        xmlSchematronPErrMemory(NULL, "allocating schema parser context",
+                                NULL);
+        return (NULL);
+    }
+    memset(ret, 0, sizeof(xmlSchematronParserCtxt));
+    ret->buffer = buffer;
+    ret->size = size;
+    ret->dict = xmlDictCreate();
+    ret->xctxt = xmlXPathNewContext(NULL);
+    if (ret->xctxt == NULL) {
+        xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context",
+                                NULL);
+	xmlSchematronFreeParserCtxt(ret);
+        return (NULL);
+    }
+    return (ret);
+}
+
+/**
+ * xmlSchematronNewDocParserCtxt:
+ * @doc:  a preparsed document tree
+ *
+ * Create an XML Schematrons parse context for that document.
+ * NB. The document may be modified during the parsing process.
+ *
+ * Returns the parser context or NULL in case of error
+ */
+xmlSchematronParserCtxtPtr
+xmlSchematronNewDocParserCtxt(xmlDocPtr doc)
+{
+    xmlSchematronParserCtxtPtr ret;
+
+    if (doc == NULL)
+        return (NULL);
+
+    ret =
+        (xmlSchematronParserCtxtPtr)
+        xmlMalloc(sizeof(xmlSchematronParserCtxt));
+    if (ret == NULL) {
+        xmlSchematronPErrMemory(NULL, "allocating schema parser context",
+                                NULL);
+        return (NULL);
+    }
+    memset(ret, 0, sizeof(xmlSchematronParserCtxt));
+    ret->doc = doc;
+    ret->dict = xmlDictCreate();
+    /* The application has responsibility for the document */
+    ret->preserve = 1;
+    ret->xctxt = xmlXPathNewContext(doc);
+    if (ret->xctxt == NULL) {
+        xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context",
+                                NULL);
+	xmlSchematronFreeParserCtxt(ret);
+        return (NULL);
+    }
+
+    return (ret);
+}
+
+/**
+ * xmlSchematronFreeParserCtxt:
+ * @ctxt:  the schema parser context
+ *
+ * Free the resources associated to the schema parser context
+ */
+void
+xmlSchematronFreeParserCtxt(xmlSchematronParserCtxtPtr ctxt)
+{
+    if (ctxt == NULL)
+        return;
+    if (ctxt->doc != NULL && !ctxt->preserve)
+        xmlFreeDoc(ctxt->doc);
+    if (ctxt->xctxt != NULL) {
+        xmlXPathFreeContext(ctxt->xctxt);
+    }
+    if (ctxt->namespaces != NULL)
+        xmlFree(ctxt->namespaces);
+    xmlDictFree(ctxt->dict);
+    xmlFree(ctxt);
+}
+
+/**
+ * xmlSchematronPushInclude:
+ * @ctxt:  the schema parser context
+ * @doc:  the included document
+ * @cur:  the current include node
+ *
+ * Add an included document
+ */
+static void
+xmlSchematronPushInclude(xmlSchematronParserCtxtPtr ctxt,
+                        xmlDocPtr doc, xmlNodePtr cur)
+{
+    if (ctxt->includes == NULL) {
+        ctxt->maxIncludes = 10;
+        ctxt->includes = (xmlNodePtr *)
+	    xmlMalloc(ctxt->maxIncludes * 2 * sizeof(xmlNodePtr));
+	if (ctxt->includes == NULL) {
+	    xmlSchematronPErrMemory(NULL, "allocating parser includes",
+				    NULL);
+	    return;
+	}
+        ctxt->nbIncludes = 0;
+    } else if (ctxt->nbIncludes + 2 >= ctxt->maxIncludes) {
+        xmlNodePtr *tmp;
+
+	tmp = (xmlNodePtr *)
+	    xmlRealloc(ctxt->includes, ctxt->maxIncludes * 4 *
+	               sizeof(xmlNodePtr));
+	if (tmp == NULL) {
+	    xmlSchematronPErrMemory(NULL, "allocating parser includes",
+				    NULL);
+	    return;
+	}
+        ctxt->includes = tmp;
+	ctxt->maxIncludes *= 2;
+    }
+    ctxt->includes[2 * ctxt->nbIncludes] = cur;
+    ctxt->includes[2 * ctxt->nbIncludes + 1] = (xmlNodePtr) doc;
+    ctxt->nbIncludes++;
+}
+
+/**
+ * xmlSchematronPopInclude:
+ * @ctxt:  the schema parser context
+ *
+ * Pop an include level. The included document is being freed
+ *
+ * Returns the node immediately following the include or NULL if the
+ *         include list was empty.
+ */
+static xmlNodePtr
+xmlSchematronPopInclude(xmlSchematronParserCtxtPtr ctxt)
+{
+    xmlDocPtr doc;
+    xmlNodePtr ret;
+
+    if (ctxt->nbIncludes <= 0)
+        return(NULL);
+    ctxt->nbIncludes--;
+    doc = (xmlDocPtr) ctxt->includes[2 * ctxt->nbIncludes + 1];
+    ret = ctxt->includes[2 * ctxt->nbIncludes];
+    xmlFreeDoc(doc);
+    if (ret != NULL)
+	ret = ret->next;
+    if (ret == NULL)
+        return(xmlSchematronPopInclude(ctxt));
+    return(ret);
+}
+
+/**
+ * xmlSchematronAddNamespace:
+ * @ctxt:  the schema parser context
+ * @prefix:  the namespace prefix
+ * @ns:  the namespace name
+ *
+ * Add a namespace definition in the context
+ */
+static void
+xmlSchematronAddNamespace(xmlSchematronParserCtxtPtr ctxt,
+                          const xmlChar *prefix, const xmlChar *ns)
+{
+    if (ctxt->namespaces == NULL) {
+        ctxt->maxNamespaces = 10;
+        ctxt->namespaces = (const xmlChar **)
+	    xmlMalloc(ctxt->maxNamespaces * 2 * sizeof(const xmlChar *));
+	if (ctxt->namespaces == NULL) {
+	    xmlSchematronPErrMemory(NULL, "allocating parser namespaces",
+				    NULL);
+	    return;
+	}
+        ctxt->nbNamespaces = 0;
+    } else if (ctxt->nbNamespaces + 2 >= ctxt->maxNamespaces) {
+        const xmlChar **tmp;
+
+	tmp = (const xmlChar **)
+	    xmlRealloc(ctxt->namespaces, ctxt->maxNamespaces * 4 *
+	               sizeof(const xmlChar *));
+	if (tmp == NULL) {
+	    xmlSchematronPErrMemory(NULL, "allocating parser namespaces",
+				    NULL);
+	    return;
+	}
+        ctxt->namespaces = tmp;
+	ctxt->maxNamespaces *= 2;
+    }
+    ctxt->namespaces[2 * ctxt->nbNamespaces] = 
+        xmlDictLookup(ctxt->dict, ns, -1);
+    ctxt->namespaces[2 * ctxt->nbNamespaces + 1] = 
+        xmlDictLookup(ctxt->dict, prefix, -1);
+    ctxt->nbNamespaces++;
+    ctxt->namespaces[2 * ctxt->nbNamespaces] = NULL;
+    ctxt->namespaces[2 * ctxt->nbNamespaces + 1] = NULL;
+
+}
+
+/**
+ * xmlSchematronParseRule:
+ * @ctxt:  a schema validation context
+ * @rule:  the rule node
+ *
+ * parse a rule element
+ */
+static void
+xmlSchematronParseRule(xmlSchematronParserCtxtPtr ctxt, xmlNodePtr rule)
+{
+    xmlNodePtr cur;
+    int nbChecks = 0;
+    xmlChar *test;
+    xmlChar *context;
+    xmlSchematronRulePtr ruleptr;
+    xmlSchematronTestPtr testptr;
+
+    if ((ctxt == NULL) || (rule == NULL)) return;
+
+    context = xmlGetNoNsProp(rule, BAD_CAST "context");
+    if (context == NULL) {
+	xmlSchematronPErr(ctxt, rule,
+	    XML_SCHEMAP_NOROOT,
+	    "rule has no context attribute",
+	    NULL, NULL);
+	return;
+    } else if (context[0] == 0) {
+	xmlSchematronPErr(ctxt, rule,
+	    XML_SCHEMAP_NOROOT,
+	    "rule has an empty context attribute",
+	    NULL, NULL);
+	xmlFree(context);
+	return;
+    } else {
+	ruleptr = xmlSchematronAddRule(ctxt, ctxt->schema, rule, context);
+	if (ruleptr == NULL) {
+	    xmlFree(context);
+	    return;
+	}
+    }
+
+    cur = rule->children;
+    NEXT_SCHEMATRON(cur);
+    while (cur != NULL) {
+	if (IS_SCHEMATRON(cur, "assert")) {
+	    nbChecks++;
+	    test = xmlGetNoNsProp(cur, BAD_CAST "test");
+	    if (test == NULL) {
+		xmlSchematronPErr(ctxt, cur,
+		    XML_SCHEMAP_NOROOT,
+		    "assert has no test attribute",
+		    NULL, NULL);
+	    } else if (test[0] == 0) {
+		xmlSchematronPErr(ctxt, cur,
+		    XML_SCHEMAP_NOROOT,
+		    "assert has an empty test attribute",
+		    NULL, NULL);
+		xmlFree(test);
+	    } else {
+		testptr = xmlSchematronAddTest(ctxt, XML_SCHEMATRON_ASSERT,
+		                               ruleptr, cur, test);
+		if (testptr == NULL)
+		    xmlFree(test);
+	    }
+	} else if (IS_SCHEMATRON(cur, "report")) {
+	    nbChecks++;
+	    test = xmlGetNoNsProp(cur, BAD_CAST "test");
+	    if (test == NULL) {
+		xmlSchematronPErr(ctxt, cur,
+		    XML_SCHEMAP_NOROOT,
+		    "assert has no test attribute",
+		    NULL, NULL);
+	    } else if (test[0] == 0) {
+		xmlSchematronPErr(ctxt, cur,
+		    XML_SCHEMAP_NOROOT,
+		    "assert has an empty test attribute",
+		    NULL, NULL);
+		xmlFree(test);
+	    } else {
+		testptr = xmlSchematronAddTest(ctxt, XML_SCHEMATRON_REPORT,
+		                               ruleptr, cur, test);
+		if (testptr == NULL)
+		    xmlFree(test);
+	    }
+	} else {
+	    xmlSchematronPErr(ctxt, cur,
+		XML_SCHEMAP_NOROOT,
+		"Expecting an assert or a report element instead of %s",
+		cur->name, NULL);
+	}
+	cur = cur->next;
+	NEXT_SCHEMATRON(cur);
+    }
+    if (nbChecks == 0) {
+	xmlSchematronPErr(ctxt, rule,
+	    XML_SCHEMAP_NOROOT,
+	    "rule has no assert nor report element", NULL, NULL);
+    }
+}
+
+/**
+ * xmlSchematronParsePattern:
+ * @ctxt:  a schema validation context
+ * @pat:  the pattern node
+ *
+ * parse a pattern element
+ */
+static void
+xmlSchematronParsePattern(xmlSchematronParserCtxtPtr ctxt, xmlNodePtr pat)
+{
+    xmlNodePtr cur;
+    int nbRules = 0;
+
+    if ((ctxt == NULL) || (pat == NULL)) return;
+
+    cur = pat->children;
+    NEXT_SCHEMATRON(cur);
+    while (cur != NULL) {
+	if (IS_SCHEMATRON(cur, "rule")) {
+	    xmlSchematronParseRule(ctxt, cur);
+	    nbRules++;
+	} else {
+	    xmlSchematronPErr(ctxt, cur,
+		XML_SCHEMAP_NOROOT,
+		"Expecting a rule element instead of %s", cur->name, NULL);
+	}
+	cur = cur->next;
+	NEXT_SCHEMATRON(cur);
+    }
+    if (nbRules == 0) {
+	xmlSchematronPErr(ctxt, pat,
+	    XML_SCHEMAP_NOROOT,
+	    "Pattern has no rule element", NULL, NULL);
+    }
+}
+
+/**
+ * xmlSchematronLoadInclude:
+ * @ctxt:  a schema validation context
+ * @cur:  the include element
+ *
+ * Load the include document, Push the current pointer
+ *
+ * Returns the updated node pointer
+ */
+static xmlNodePtr
+xmlSchematronLoadInclude(xmlSchematronParserCtxtPtr ctxt, xmlNodePtr cur)
+{
+    xmlNodePtr ret = NULL;
+    xmlDocPtr doc = NULL;
+    xmlChar *href = NULL;
+    xmlChar *base = NULL;
+    xmlChar *URI = NULL;
+
+    if ((ctxt == NULL) || (cur == NULL))
+        return(NULL);
+
+    href = xmlGetNoNsProp(cur, BAD_CAST "href");
+    if (href == NULL) {
+	xmlSchematronPErr(ctxt, cur,
+	    XML_SCHEMAP_NOROOT,
+	    "Include has no href attribute", NULL, NULL);
+	return(cur->next);
+    }
+
+    /* do the URI base composition, load and find the root */
+    base = xmlNodeGetBase(cur->doc, cur);
+    URI = xmlBuildURI(href, base);
+    doc = xmlReadFile((const char *) URI, NULL, SCHEMATRON_PARSE_OPTIONS);
+    if (doc == NULL) {
+	xmlSchematronPErr(ctxt, cur,
+		      XML_SCHEMAP_FAILED_LOAD,
+		      "could not load include '%s'.\n",
+		      URI, NULL);
+	goto done;
+    }
+    ret = xmlDocGetRootElement(doc);
+    if (ret == NULL) {
+	xmlSchematronPErr(ctxt, cur,
+		      XML_SCHEMAP_FAILED_LOAD,
+		      "could not find root from include '%s'.\n",
+		      URI, NULL);
+	goto done;
+    }
+
+    /* Success, push the include for rollback on exit */
+    xmlSchematronPushInclude(ctxt, doc, cur);
+
+done:
+    if (ret == NULL) {
+        if (doc != NULL)
+	    xmlFreeDoc(doc);
+    }
+    if (href == NULL)
+        xmlFree(href);
+    if (base == NULL)
+        xmlFree(base);
+    if (URI == NULL)
+        xmlFree(URI);
+    return(ret);
+}
+
+/**
+ * xmlSchematronParse:
+ * @ctxt:  a schema validation context
+ *
+ * parse a schema definition resource and build an internal
+ * XML Shema struture which can be used to validate instances.
+ *
+ * Returns the internal XML Schematron structure built from the resource or
+ *         NULL in case of error
+ */
+xmlSchematronPtr
+xmlSchematronParse(xmlSchematronParserCtxtPtr ctxt)
+{
+    xmlSchematronPtr ret = NULL;
+    xmlDocPtr doc;
+    xmlNodePtr root, cur;
+    int preserve = 0;
+
+    if (ctxt == NULL)
+        return (NULL);
+
+    ctxt->nberrors = 0;
+
+    /*
+     * First step is to parse the input document into an DOM/Infoset
+     */
+    if (ctxt->URL != NULL) {
+        doc = xmlReadFile((const char *) ctxt->URL, NULL,
+	                  SCHEMATRON_PARSE_OPTIONS);
+        if (doc == NULL) {
+	    xmlSchematronPErr(ctxt, NULL,
+			  XML_SCHEMAP_FAILED_LOAD,
+                          "xmlSchematronParse: could not load '%s'.\n",
+                          ctxt->URL, NULL);
+            return (NULL);
+        }
+    } else if (ctxt->buffer != NULL) {
+        doc = xmlReadMemory(ctxt->buffer, ctxt->size, NULL, NULL,
+	                    SCHEMATRON_PARSE_OPTIONS);
+        if (doc == NULL) {
+	    xmlSchematronPErr(ctxt, NULL,
+			  XML_SCHEMAP_FAILED_PARSE,
+                          "xmlSchematronParse: could not parse.\n",
+                          NULL, NULL);
+            return (NULL);
+        }
+        doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
+        ctxt->URL = xmlDictLookup(ctxt->dict, BAD_CAST "in_memory_buffer", -1);
+    } else if (ctxt->doc != NULL) {
+        doc = ctxt->doc;
+	preserve = 1;
+    } else {
+	xmlSchematronPErr(ctxt, NULL,
+		      XML_SCHEMAP_NOTHING_TO_PARSE,
+		      "xmlSchematronParse: could not parse.\n",
+		      NULL, NULL);
+        return (NULL);
+    }
+
+    /*
+     * Then extract the root and Schematron parse it
+     */
+    root = xmlDocGetRootElement(doc);
+    if (root == NULL) {
+	xmlSchematronPErr(ctxt, (xmlNodePtr) doc,
+		      XML_SCHEMAP_NOROOT,
+		      "The schema has no document element.\n", NULL, NULL);
+	if (!preserve) {
+	    xmlFreeDoc(doc);
+	}
+        return (NULL);
+    }
+
+    if (!IS_SCHEMATRON(root, "schema")) {
+	xmlSchematronPErr(ctxt, root,
+	    XML_SCHEMAP_NOROOT,
+	    "The XML document '%s' is not a XML schematron document",
+	    ctxt->URL, NULL);
+	goto exit;
+    }
+    ret = xmlSchematronNewSchematron(ctxt);
+    if (ret == NULL)
+        goto exit;
+    ctxt->schema = ret;
+
+    /*
+     * scan the schema elements
+     */
+    cur = root->children;
+    NEXT_SCHEMATRON(cur);
+    if (IS_SCHEMATRON(cur, "title")) {
+        xmlChar *title = xmlNodeGetContent(cur);
+	if (title != NULL) {
+	    ret->title = xmlDictLookup(ret->dict, title, -1);
+	    xmlFree(title);
+	}
+	cur = cur->next;
+	NEXT_SCHEMATRON(cur);
+    }
+    while (IS_SCHEMATRON(cur, "ns")) {
+        xmlChar *prefix = xmlGetNoNsProp(cur, BAD_CAST "prefix");
+        xmlChar *uri = xmlGetNoNsProp(cur, BAD_CAST "uri");
+	if ((uri == NULL) || (uri[0] == 0)) {
+	    xmlSchematronPErr(ctxt, cur,
+		XML_SCHEMAP_NOROOT,
+		"ns element has no uri", NULL, NULL);
+	}
+	if ((prefix == NULL) || (prefix[0] == 0)) {
+	    xmlSchematronPErr(ctxt, cur,
+		XML_SCHEMAP_NOROOT,
+		"ns element has no prefix", NULL, NULL);
+	}
+	if ((prefix) && (uri)) {
+	    xmlXPathRegisterNs(ctxt->xctxt, prefix, uri);
+	    xmlSchematronAddNamespace(ctxt, prefix, uri);
+	    ret->nbNs++;
+	}
+	if (uri)
+	    xmlFree(uri);
+	if (prefix)
+	    xmlFree(prefix);
+	cur = cur->next;
+	NEXT_SCHEMATRON(cur);
+    }
+    while (cur != NULL) {
+	if (IS_SCHEMATRON(cur, "pattern")) {
+	    xmlSchematronParsePattern(ctxt, cur);
+	    ret->nbPattern++;
+	} else {
+	    xmlSchematronPErr(ctxt, cur,
+		XML_SCHEMAP_NOROOT,
+		"Expecting a pattern element instead of %s", cur->name, NULL);
+	}
+	cur = cur->next;
+	NEXT_SCHEMATRON(cur);
+    }
+    if (ret->nbPattern == 0) {
+	xmlSchematronPErr(ctxt, root,
+	    XML_SCHEMAP_NOROOT,
+	    "The schematron document '%s' has no pattern",
+	    ctxt->URL, NULL);
+	goto exit;
+    }
+
+exit:
+    if (!preserve) {
+	xmlFreeDoc(doc);
+    }
+    if (ctxt->nberrors != 0) {
+        xmlSchematronFree(ret);
+        ret = NULL;
+    } else {
+        ret->namespaces = ctxt->namespaces;
+        ret->nbNamespaces = ctxt->nbNamespaces;
+	ctxt->namespaces = NULL;
+    }
+    return (ret);
+}
+
+/************************************************************************
+ *									*
+ *		Schematrontron Reports handler				*
+ *									*
+ ************************************************************************/
+
+static void
+xmlSchematronReportSuccess(xmlSchematronValidCtxtPtr ctxt, 
+			   xmlSchematronTestPtr test, xmlNodePtr cur) {
+}
+
+/************************************************************************
+ *									*
+ *		Validation against a Schematrontron				*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlSchematronNewValidCtxt:
+ * @schema:  a precompiled XML Schematrons
+ * @options: a set of xmlSchematronValidOptions
+ *
+ * Create an XML Schematrons validation context based on the given schema.
+ *
+ * Returns the validation context or NULL in case of error
+ */
+xmlSchematronValidCtxtPtr
+xmlSchematronNewValidCtxt(xmlSchematronPtr schema, int options)
+{
+    int i;
+    xmlSchematronValidCtxtPtr ret;
+
+    ret =
+        (xmlSchematronValidCtxtPtr)
+        xmlMalloc(sizeof(xmlSchematronValidCtxt));
+    if (ret == NULL) {
+        xmlSchematronVErrMemory(NULL, "allocating validation context",
+                                NULL);
+        return (NULL);
+    }
+    memset(ret, 0, sizeof(xmlSchematronValidCtxt));
+    ret->type = XML_STRON_CTXT_VALIDATOR;
+    ret->schema = schema;
+    ret->xctxt = xmlXPathNewContext(NULL);
+    if (ret->xctxt == NULL) {
+        xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context",
+                                NULL);
+	xmlSchematronFreeValidCtxt(ret);
+        return (NULL);
+    }
+    for (i = 0;i < schema->nbNamespaces;i++) {
+        if ((schema->namespaces[2 * i] == NULL) ||
+            (schema->namespaces[2 * i + 1] == NULL))
+	    break;
+	xmlXPathRegisterNs(ret->xctxt, schema->namespaces[2 * i + 1],
+	                   schema->namespaces[2 * i]);
+    }
+    return (ret);
+}
+
+/**
+ * xmlSchematronFreeValidCtxt:
+ * @ctxt:  the schema validation context
+ *
+ * Free the resources associated to the schema validation context
+ */
+void
+xmlSchematronFreeValidCtxt(xmlSchematronValidCtxtPtr ctxt)
+{
+    if (ctxt == NULL)
+        return;
+    if (ctxt->xctxt != NULL)
+        xmlXPathFreeContext(ctxt->xctxt);
+    if (ctxt->dict != NULL)
+        xmlDictFree(ctxt->dict);
+    xmlFree(ctxt);
+}
+
+static xmlNodePtr
+xmlSchematronNextNode(xmlNodePtr cur) {
+    if (cur->children != NULL) {
+	/*
+	 * Do not descend on entities declarations
+	 */
+	if (cur->children->type != XML_ENTITY_DECL) {
+	    cur = cur->children;
+	    /*
+	     * Skip DTDs
+	     */
+	    if (cur->type != XML_DTD_NODE)
+		return(cur);
+	}
+    }
+
+    while (cur->next != NULL) {
+	cur = cur->next;
+	if ((cur->type != XML_ENTITY_DECL) &&
+	    (cur->type != XML_DTD_NODE))
+	    return(cur);
+    }
+    
+    do {
+	cur = cur->parent;
+	if (cur == NULL) return(NULL);
+	if (cur->type == XML_DOCUMENT_NODE) return(NULL);
+	if (cur->next != NULL) {
+	    cur = cur->next;
+	    return(cur);
+	}
+    } while (cur != NULL);
+    return(cur);
+}
+
+/**
+ * xmlSchematronRunTest:
+ * @ctxt:  the schema validation context
+ * @test:  the current test
+ * @instance:  the document instace tree 
+ * @cur:  the current node in the instance
+ *
+ * Validate a rule against a tree instance at a given position
+ *
+ * Returns 1 in case of success, 0 if error and -1 in case of internal error
+ */
+static int
+xmlSchematronRunTest(xmlSchematronValidCtxtPtr ctxt,
+     xmlSchematronTestPtr test, xmlDocPtr instance, xmlNodePtr cur)
+{
+    xmlXPathObjectPtr ret;
+    int failed;
+
+    failed = 0;
+    ctxt->xctxt->doc = instance;
+    ctxt->xctxt->node = cur;
+    ret = xmlXPathCompiledEval(test->comp, ctxt->xctxt);
+    if (ret == NULL) {
+	failed = 1;
+    } else switch (ret->type) {
+	case XPATH_XSLT_TREE:
+	case XPATH_NODESET:
+	    if ((ret->nodesetval == NULL) ||
+		(ret->nodesetval->nodeNr == 0))
+		failed = 1;
+	    break;
+	case XPATH_BOOLEAN:
+	    failed = !ret->boolval;
+	    break;
+	case XPATH_NUMBER:
+	    if ((xmlXPathIsNaN(ret->floatval)) ||
+		(ret->floatval == 0.0))
+		failed = 1;
+	    break;
+	case XPATH_STRING:
+	    if ((ret->stringval == NULL) ||
+		(ret->stringval[0] == 0))
+		failed = 1;
+	    break;
+	case XPATH_UNDEFINED:
+	case XPATH_POINT:
+	case XPATH_RANGE:
+	case XPATH_LOCATIONSET:
+	case XPATH_USERS:
+	    failed = 1;
+	    break;
+    }
+    if (test->type == XML_SCHEMATRON_REPORT) {
+	if (!failed) {
+	    printf("report failed\n");
+	}
+    } else {
+	if (failed) {
+	    printf("assert failed\n");
+	}
+    }
+
+    return(!failed);
+}
+
+/**
+ * xmlSchematronValidateDoc:
+ * @ctxt:  the schema validation context
+ * @instance:  the document instace tree 
+ *
+ * Validate a tree instance against the schematron
+ *
+ * Returns 0 in case of success, -1 in case of internal error
+ *         and an error count otherwise.
+ */
+int
+xmlSchematronValidateDoc(xmlSchematronValidCtxtPtr ctxt, xmlDocPtr instance)
+{
+    xmlNodePtr cur;
+    xmlSchematronRulePtr rule;
+    xmlSchematronTestPtr test;
+
+    if ((ctxt == NULL) || (ctxt->schema == NULL) ||
+        (ctxt->schema->rules == NULL) || (instance == NULL))
+        return(-1);
+    ctxt->nberrors = 0;
+    cur = xmlDocGetRootElement(instance);
+    while (cur != NULL) {
+        rule = ctxt->schema->rules;
+	while (rule != NULL) {
+	    if (xmlPatternMatch(rule->pattern, cur) == 1) {
+	        printf("%s matches\n", cur->name);
+	        test = rule->tests;
+		while (test != NULL) {
+		    xmlSchematronRunTest(ctxt, test, instance, cur);
+		    test = test->next;
+		}
+	    }
+	    rule = rule->next;
+	}
+        
+        cur = xmlSchematronNextNode(cur);
+    }
+    return(ctxt->nberrors);
+}
+
+#ifdef STANDALONE
+int
+main(void)
+{
+    int ret;
+    xmlDocPtr instance;
+    xmlSchematronParserCtxtPtr pctxt;
+    xmlSchematronValidCtxtPtr vctxt;
+    xmlSchematronPtr schema = NULL;
+
+    pctxt = xmlSchematronNewParserCtxt("tst.sct");
+    if (pctxt == NULL) {
+        fprintf(stderr, "failed to build schematron parser\n");
+    } else {
+        schema = xmlSchematronParse(pctxt);
+	if (schema == NULL) {
+	    fprintf(stderr, "failed to compile schematron\n");
+	}
+	xmlSchematronFreeParserCtxt(pctxt);
+    }
+    instance = xmlReadFile("tst.sct", NULL,
+                           XML_PARSE_NOENT | XML_PARSE_NOCDATA);
+    if (instance == NULL) {
+	fprintf(stderr, "failed to parse instance\n");
+    }
+    if ((schema != NULL) && (instance != NULL)) {
+        vctxt = xmlSchematronNewValidCtxt(schema);
+	if (vctxt == NULL) {
+	    fprintf(stderr, "failed to build schematron validator\n");
+	} else {
+	    ret = xmlSchematronValidateDoc(vctxt, instance);
+	    xmlSchematronFreeValidCtxt(vctxt);
+	}
+    }
+    xmlSchematronFree(schema);
+    xmlFreeDoc(instance);
+
+    xmlCleanupParser();
+    xmlMemoryDump();
+
+    return (0);
+}
+#endif
+#endif /* LIBXML_SCHEMATRON_ENABLED */
diff --git a/xpath.c b/xpath.c
index 0029734..f6e9826 100644
--- a/xpath.c
+++ b/xpath.c
@@ -8926,6 +8926,12 @@
 	if (test == 0)
 	    return;
 
+        if ((prefix != NULL) && (ctxt->context != NULL) &&
+	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
+	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
+		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
+	    }
+	}
 #ifdef DEBUG_STEP
 	xmlGenericError(xmlGenericErrorContext,
 		"Basis : computing new set\n");