|
Packit |
423ecb |
/*
|
|
Packit |
423ecb |
* schematron.c : implementation of the Schematron schema validity checking
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* See Copyright for the status of this software.
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Daniel Veillard <daniel@veillard.com>
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/*
|
|
Packit |
423ecb |
* TODO:
|
|
Packit |
423ecb |
* + double check the semantic, especially
|
|
Packit |
423ecb |
* - multiple rules applying in a single pattern/node
|
|
Packit |
423ecb |
* - the semantic of libxml2 patterns vs. XSLT production referenced
|
|
Packit |
423ecb |
* by the spec.
|
|
Packit |
423ecb |
* + export of results in SVRL
|
|
Packit |
423ecb |
* + full parsing and coverage of the spec, conformance of the input to the
|
|
Packit |
423ecb |
* spec
|
|
Packit |
423ecb |
* + divergences between the draft and the ISO proposed standard :-(
|
|
Packit |
423ecb |
* + hook and test include
|
|
Packit |
423ecb |
* + try and compare with the XSLT version
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
#define IN_LIBXML
|
|
Packit |
423ecb |
#include "libxml.h"
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
#ifdef LIBXML_SCHEMATRON_ENABLED
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
#include <string.h>
|
|
Packit |
423ecb |
#include <libxml/parser.h>
|
|
Packit |
423ecb |
#include <libxml/tree.h>
|
|
Packit |
423ecb |
#include <libxml/uri.h>
|
|
Packit |
423ecb |
#include <libxml/xpath.h>
|
|
Packit |
423ecb |
#include <libxml/xpathInternals.h>
|
|
Packit |
423ecb |
#include <libxml/pattern.h>
|
|
Packit |
423ecb |
#include <libxml/schematron.h>
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
#define SCHEMATRON_PARSE_OPTIONS XML_PARSE_NOENT
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
#define SCT_OLD_NS BAD_CAST "http://www.ascc.net/xml/schematron"
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
#define XML_SCHEMATRON_NS BAD_CAST "http://purl.oclc.org/dsdl/schematron"
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
static const xmlChar *xmlSchematronNs = XML_SCHEMATRON_NS;
|
|
Packit |
423ecb |
static const xmlChar *xmlOldSchematronNs = SCT_OLD_NS;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
#define IS_SCHEMATRON(node, elem) \
|
|
Packit |
423ecb |
((node != NULL) && (node->type == XML_ELEMENT_NODE ) && \
|
|
Packit |
423ecb |
(node->ns != NULL) && \
|
|
Packit |
423ecb |
(xmlStrEqual(node->name, (const xmlChar *) elem)) && \
|
|
Packit |
423ecb |
((xmlStrEqual(node->ns->href, xmlSchematronNs)) || \
|
|
Packit |
423ecb |
(xmlStrEqual(node->ns->href, xmlOldSchematronNs))))
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
#define NEXT_SCHEMATRON(node) \
|
|
Packit |
423ecb |
while (node != NULL) { \
|
|
Packit |
423ecb |
if ((node->type == XML_ELEMENT_NODE ) && (node->ns != NULL) && \
|
|
Packit |
423ecb |
((xmlStrEqual(node->ns->href, xmlSchematronNs)) || \
|
|
Packit |
423ecb |
(xmlStrEqual(node->ns->href, xmlOldSchematronNs)))) \
|
|
Packit |
423ecb |
break; \
|
|
Packit |
423ecb |
node = node->next; \
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* TODO:
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* macro to flag unimplemented blocks
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
#define TODO \
|
|
Packit |
423ecb |
xmlGenericError(xmlGenericErrorContext, \
|
|
Packit |
423ecb |
"Unimplemented block at %s:%d\n", \
|
|
Packit |
423ecb |
__FILE__, __LINE__);
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
typedef enum {
|
|
Packit |
423ecb |
XML_SCHEMATRON_ASSERT=1,
|
|
Packit |
423ecb |
XML_SCHEMATRON_REPORT=2
|
|
Packit |
423ecb |
} xmlSchematronTestType;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* _xmlSchematronTest:
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* A Schematrons test, either an assert or a report
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
typedef struct _xmlSchematronTest xmlSchematronTest;
|
|
Packit |
423ecb |
typedef xmlSchematronTest *xmlSchematronTestPtr;
|
|
Packit |
423ecb |
struct _xmlSchematronTest {
|
|
Packit |
423ecb |
xmlSchematronTestPtr next; /* the next test in the list */
|
|
Packit |
423ecb |
xmlSchematronTestType type; /* the test type */
|
|
Packit |
423ecb |
xmlNodePtr node; /* the node in the tree */
|
|
Packit |
423ecb |
xmlChar *test; /* the expression to test */
|
|
Packit |
423ecb |
xmlXPathCompExprPtr comp; /* the compiled expression */
|
|
Packit |
423ecb |
xmlChar *report; /* the message to report */
|
|
Packit |
423ecb |
};
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* _xmlSchematronRule:
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* A Schematrons rule
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
typedef struct _xmlSchematronRule xmlSchematronRule;
|
|
Packit |
423ecb |
typedef xmlSchematronRule *xmlSchematronRulePtr;
|
|
Packit |
423ecb |
struct _xmlSchematronRule {
|
|
Packit |
423ecb |
xmlSchematronRulePtr next; /* the next rule in the list */
|
|
Packit |
423ecb |
xmlSchematronRulePtr patnext;/* the next rule in the pattern list */
|
|
Packit |
423ecb |
xmlNodePtr node; /* the node in the tree */
|
|
Packit |
423ecb |
xmlChar *context; /* the context evaluation rule */
|
|
Packit |
423ecb |
xmlSchematronTestPtr tests; /* the list of tests */
|
|
Packit |
423ecb |
xmlPatternPtr pattern; /* the compiled pattern associated */
|
|
Packit |
423ecb |
xmlChar *report; /* the message to report */
|
|
Packit |
423ecb |
};
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* _xmlSchematronPattern:
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* A Schematrons pattern
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
typedef struct _xmlSchematronPattern xmlSchematronPattern;
|
|
Packit |
423ecb |
typedef xmlSchematronPattern *xmlSchematronPatternPtr;
|
|
Packit |
423ecb |
struct _xmlSchematronPattern {
|
|
Packit |
423ecb |
xmlSchematronPatternPtr next;/* the next pattern in the list */
|
|
Packit |
423ecb |
xmlSchematronRulePtr rules; /* the list of rules */
|
|
Packit |
423ecb |
xmlChar *name; /* the name of the pattern */
|
|
Packit |
423ecb |
};
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* _xmlSchematron:
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* A Schematrons definition
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
struct _xmlSchematron {
|
|
Packit |
423ecb |
const xmlChar *name; /* schema name */
|
|
Packit |
423ecb |
int preserve; /* was the document passed by the user */
|
|
Packit |
423ecb |
xmlDocPtr doc; /* pointer to the parsed document */
|
|
Packit |
423ecb |
int flags; /* specific to this schematron */
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
void *_private; /* unused by the library */
|
|
Packit |
423ecb |
xmlDictPtr dict; /* the dictionary used internally */
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
const xmlChar *title; /* the title if any */
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
int nbNs; /* the number of namespaces */
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
int nbPattern; /* the number of patterns */
|
|
Packit |
423ecb |
xmlSchematronPatternPtr patterns;/* the patterns found */
|
|
Packit |
423ecb |
xmlSchematronRulePtr rules; /* the rules gathered */
|
|
Packit |
423ecb |
int nbNamespaces; /* number of namespaces in the array */
|
|
Packit |
423ecb |
int maxNamespaces; /* size of the array */
|
|
Packit |
423ecb |
const xmlChar **namespaces; /* the array of namespaces */
|
|
Packit |
423ecb |
};
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* xmlSchematronValidCtxt:
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* A Schematrons validation context
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
struct _xmlSchematronValidCtxt {
|
|
Packit |
423ecb |
int type;
|
|
Packit |
423ecb |
int flags; /* an or of xmlSchematronValidOptions */
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
xmlDictPtr dict;
|
|
Packit |
423ecb |
int nberrors;
|
|
Packit |
423ecb |
int err;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
xmlSchematronPtr schema;
|
|
Packit |
423ecb |
xmlXPathContextPtr xctxt;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
FILE *outputFile; /* if using XML_SCHEMATRON_OUT_FILE */
|
|
Packit |
423ecb |
xmlBufferPtr outputBuffer; /* if using XML_SCHEMATRON_OUT_BUFFER */
|
|
Packit |
423ecb |
#ifdef LIBXML_OUTPUT_ENABLED
|
|
Packit |
423ecb |
xmlOutputWriteCallback iowrite; /* if using XML_SCHEMATRON_OUT_IO */
|
|
Packit |
423ecb |
xmlOutputCloseCallback ioclose;
|
|
Packit |
423ecb |
#endif
|
|
Packit |
423ecb |
void *ioctx;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/* error reporting data */
|
|
Packit |
423ecb |
void *userData; /* user specific data block */
|
|
Packit |
423ecb |
xmlSchematronValidityErrorFunc error;/* the callback in case of errors */
|
|
Packit |
423ecb |
xmlSchematronValidityWarningFunc warning;/* callback in case of warning */
|
|
Packit |
423ecb |
xmlStructuredErrorFunc serror; /* the structured function */
|
|
Packit |
423ecb |
};
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
struct _xmlSchematronParserCtxt {
|
|
Packit |
423ecb |
int type;
|
|
Packit |
423ecb |
const xmlChar *URL;
|
|
Packit |
423ecb |
xmlDocPtr doc;
|
|
Packit |
423ecb |
int preserve; /* Whether the doc should be freed */
|
|
Packit |
423ecb |
const char *buffer;
|
|
Packit |
423ecb |
int size;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
xmlDictPtr dict; /* dictionary for interned string names */
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
int nberrors;
|
|
Packit |
423ecb |
int err;
|
|
Packit |
423ecb |
xmlXPathContextPtr xctxt; /* the XPath context used for compilation */
|
|
Packit |
423ecb |
xmlSchematronPtr schema;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
int nbNamespaces; /* number of namespaces in the array */
|
|
Packit |
423ecb |
int maxNamespaces; /* size of the array */
|
|
Packit |
423ecb |
const xmlChar **namespaces; /* the array of namespaces */
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
int nbIncludes; /* number of includes in the array */
|
|
Packit |
423ecb |
int maxIncludes; /* size of the array */
|
|
Packit |
423ecb |
xmlNodePtr *includes; /* the array of includes */
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/* error reporting data */
|
|
Packit |
423ecb |
void *userData; /* user specific data block */
|
|
Packit |
423ecb |
xmlSchematronValidityErrorFunc error;/* the callback in case of errors */
|
|
Packit |
423ecb |
xmlSchematronValidityWarningFunc warning;/* callback in case of warning */
|
|
Packit |
423ecb |
xmlStructuredErrorFunc serror; /* the structured function */
|
|
Packit |
423ecb |
};
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
#define XML_STRON_CTXT_PARSER 1
|
|
Packit |
423ecb |
#define XML_STRON_CTXT_VALIDATOR 2
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/************************************************************************
|
|
Packit |
423ecb |
* *
|
|
Packit |
423ecb |
* Error reporting *
|
|
Packit |
423ecb |
* *
|
|
Packit |
423ecb |
************************************************************************/
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* xmlSchematronPErrMemory:
|
|
Packit |
423ecb |
* @node: a context node
|
|
Packit |
423ecb |
* @extra: extra informations
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Handle an out of memory condition
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
static void
|
|
Packit |
423ecb |
xmlSchematronPErrMemory(xmlSchematronParserCtxtPtr ctxt,
|
|
Packit |
423ecb |
const char *extra, xmlNodePtr node)
|
|
Packit |
423ecb |
{
|
|
Packit |
423ecb |
if (ctxt != NULL)
|
|
Packit |
423ecb |
ctxt->nberrors++;
|
|
Packit |
423ecb |
__xmlSimpleError(XML_FROM_SCHEMASP, XML_ERR_NO_MEMORY, node, NULL,
|
|
Packit |
423ecb |
extra);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* xmlSchematronPErr:
|
|
Packit |
423ecb |
* @ctxt: the parsing context
|
|
Packit |
423ecb |
* @node: the context node
|
|
Packit |
423ecb |
* @error: the error code
|
|
Packit |
423ecb |
* @msg: the error message
|
|
Packit |
423ecb |
* @str1: extra data
|
|
Packit |
423ecb |
* @str2: extra data
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Handle a parser error
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
static void LIBXML_ATTR_FORMAT(4,0)
|
|
Packit |
423ecb |
xmlSchematronPErr(xmlSchematronParserCtxtPtr ctxt, xmlNodePtr node, int error,
|
|
Packit |
423ecb |
const char *msg, const xmlChar * str1, const xmlChar * str2)
|
|
Packit |
423ecb |
{
|
|
Packit |
423ecb |
xmlGenericErrorFunc channel = NULL;
|
|
Packit |
423ecb |
xmlStructuredErrorFunc schannel = NULL;
|
|
Packit |
423ecb |
void *data = NULL;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
if (ctxt != NULL) {
|
|
Packit |
423ecb |
ctxt->nberrors++;
|
|
Packit |
423ecb |
channel = ctxt->error;
|
|
Packit |
423ecb |
data = ctxt->userData;
|
|
Packit |
423ecb |
schannel = ctxt->serror;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
__xmlRaiseError(schannel, channel, data, ctxt, node, XML_FROM_SCHEMASP,
|
|
Packit |
423ecb |
error, XML_ERR_ERROR, NULL, 0,
|
|
Packit |
423ecb |
(const char *) str1, (const char *) str2, NULL, 0, 0,
|
|
Packit |
423ecb |
msg, str1, str2);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* xmlSchematronVTypeErrMemory:
|
|
Packit |
423ecb |
* @node: a context node
|
|
Packit |
423ecb |
* @extra: extra informations
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Handle an out of memory condition
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
static void
|
|
Packit |
423ecb |
xmlSchematronVErrMemory(xmlSchematronValidCtxtPtr ctxt,
|
|
Packit |
423ecb |
const char *extra, xmlNodePtr node)
|
|
Packit |
423ecb |
{
|
|
Packit |
423ecb |
if (ctxt != NULL) {
|
|
Packit |
423ecb |
ctxt->nberrors++;
|
|
Packit |
423ecb |
ctxt->err = XML_SCHEMAV_INTERNAL;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
__xmlSimpleError(XML_FROM_SCHEMASV, XML_ERR_NO_MEMORY, node, NULL,
|
|
Packit |
423ecb |
extra);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/************************************************************************
|
|
Packit |
423ecb |
* *
|
|
Packit |
423ecb |
* Parsing and compilation of the Schematrontrons *
|
|
Packit |
423ecb |
* *
|
|
Packit |
423ecb |
************************************************************************/
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* xmlSchematronAddTest:
|
|
Packit |
423ecb |
* @ctxt: the schema parsing context
|
|
Packit |
423ecb |
* @type: the type of test
|
|
Packit |
423ecb |
* @rule: the parent rule
|
|
Packit |
423ecb |
* @node: the node hosting the test
|
|
Packit |
423ecb |
* @test: the associated test
|
|
Packit |
423ecb |
* @report: the associated report string
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Add a test to a schematron
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Returns the new pointer or NULL in case of error
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
static xmlSchematronTestPtr
|
|
Packit |
423ecb |
xmlSchematronAddTest(xmlSchematronParserCtxtPtr ctxt,
|
|
Packit |
423ecb |
xmlSchematronTestType type,
|
|
Packit |
423ecb |
xmlSchematronRulePtr rule,
|
|
Packit |
423ecb |
xmlNodePtr node, xmlChar *test, xmlChar *report)
|
|
Packit |
423ecb |
{
|
|
Packit |
423ecb |
xmlSchematronTestPtr ret;
|
|
Packit |
423ecb |
xmlXPathCompExprPtr comp;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
if ((ctxt == NULL) || (rule == NULL) || (node == NULL) ||
|
|
Packit |
423ecb |
(test == NULL))
|
|
Packit |
423ecb |
return(NULL);
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/*
|
|
Packit |
423ecb |
* try first to compile the test expression
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
comp = xmlXPathCtxtCompile(ctxt->xctxt, test);
|
|
Packit |
423ecb |
if (comp == NULL) {
|
|
Packit |
423ecb |
xmlSchematronPErr(ctxt, node,
|
|
Packit |
423ecb |
XML_SCHEMAP_NOROOT,
|
|
Packit |
423ecb |
"Failed to compile test expression %s",
|
|
Packit |
423ecb |
test, NULL);
|
|
Packit |
423ecb |
return(NULL);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
ret = (xmlSchematronTestPtr) xmlMalloc(sizeof(xmlSchematronTest));
|
|
Packit |
423ecb |
if (ret == NULL) {
|
|
Packit |
423ecb |
xmlSchematronPErrMemory(ctxt, "allocating schema test", node);
|
|
Packit |
423ecb |
return (NULL);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
memset(ret, 0, sizeof(xmlSchematronTest));
|
|
Packit |
423ecb |
ret->type = type;
|
|
Packit |
423ecb |
ret->node = node;
|
|
Packit |
423ecb |
ret->test = test;
|
|
Packit |
423ecb |
ret->comp = comp;
|
|
Packit |
423ecb |
ret->report = report;
|
|
Packit |
423ecb |
ret->next = NULL;
|
|
Packit |
423ecb |
if (rule->tests == NULL) {
|
|
Packit |
423ecb |
rule->tests = ret;
|
|
Packit |
423ecb |
} else {
|
|
Packit |
423ecb |
xmlSchematronTestPtr prev = rule->tests;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
while (prev->next != NULL)
|
|
Packit |
423ecb |
prev = prev->next;
|
|
Packit |
423ecb |
prev->next = ret;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
return (ret);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* xmlSchematronFreeTests:
|
|
Packit |
423ecb |
* @tests: a list of tests
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Free a list of tests.
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
static void
|
|
Packit |
423ecb |
xmlSchematronFreeTests(xmlSchematronTestPtr tests) {
|
|
Packit |
423ecb |
xmlSchematronTestPtr next;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
while (tests != NULL) {
|
|
Packit |
423ecb |
next = tests->next;
|
|
Packit |
423ecb |
if (tests->test != NULL)
|
|
Packit |
423ecb |
xmlFree(tests->test);
|
|
Packit |
423ecb |
if (tests->comp != NULL)
|
|
Packit |
423ecb |
xmlXPathFreeCompExpr(tests->comp);
|
|
Packit |
423ecb |
if (tests->report != NULL)
|
|
Packit |
423ecb |
xmlFree(tests->report);
|
|
Packit |
423ecb |
xmlFree(tests);
|
|
Packit |
423ecb |
tests = next;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* xmlSchematronAddRule:
|
|
Packit |
423ecb |
* @ctxt: the schema parsing context
|
|
Packit |
423ecb |
* @schema: a schema structure
|
|
Packit |
423ecb |
* @node: the node hosting the rule
|
|
Packit |
423ecb |
* @context: the associated context string
|
|
Packit |
423ecb |
* @report: the associated report string
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Add a rule to a schematron
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Returns the new pointer or NULL in case of error
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
static xmlSchematronRulePtr
|
|
Packit |
423ecb |
xmlSchematronAddRule(xmlSchematronParserCtxtPtr ctxt, xmlSchematronPtr schema,
|
|
Packit |
423ecb |
xmlSchematronPatternPtr pat, xmlNodePtr node,
|
|
Packit |
423ecb |
xmlChar *context, xmlChar *report)
|
|
Packit |
423ecb |
{
|
|
Packit |
423ecb |
xmlSchematronRulePtr ret;
|
|
Packit |
423ecb |
xmlPatternPtr pattern;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
if ((ctxt == NULL) || (schema == NULL) || (node == NULL) ||
|
|
Packit |
423ecb |
(context == NULL))
|
|
Packit |
423ecb |
return(NULL);
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/*
|
|
Packit |
423ecb |
* Try first to compile the pattern
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
pattern = xmlPatterncompile(context, ctxt->dict, XML_PATTERN_XPATH,
|
|
Packit |
423ecb |
ctxt->namespaces);
|
|
Packit |
423ecb |
if (pattern == NULL) {
|
|
Packit |
423ecb |
xmlSchematronPErr(ctxt, node,
|
|
Packit |
423ecb |
XML_SCHEMAP_NOROOT,
|
|
Packit |
423ecb |
"Failed to compile context expression %s",
|
|
Packit |
423ecb |
context, NULL);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
ret = (xmlSchematronRulePtr) xmlMalloc(sizeof(xmlSchematronRule));
|
|
Packit |
423ecb |
if (ret == NULL) {
|
|
Packit |
423ecb |
xmlSchematronPErrMemory(ctxt, "allocating schema rule", node);
|
|
Packit |
423ecb |
return (NULL);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
memset(ret, 0, sizeof(xmlSchematronRule));
|
|
Packit |
423ecb |
ret->node = node;
|
|
Packit |
423ecb |
ret->context = context;
|
|
Packit |
423ecb |
ret->pattern = pattern;
|
|
Packit |
423ecb |
ret->report = report;
|
|
Packit |
423ecb |
ret->next = NULL;
|
|
Packit |
423ecb |
if (schema->rules == NULL) {
|
|
Packit |
423ecb |
schema->rules = ret;
|
|
Packit |
423ecb |
} else {
|
|
Packit |
423ecb |
xmlSchematronRulePtr prev = schema->rules;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
while (prev->next != NULL)
|
|
Packit |
423ecb |
prev = prev->next;
|
|
Packit |
423ecb |
prev->next = ret;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
ret->patnext = NULL;
|
|
Packit |
423ecb |
if (pat->rules == NULL) {
|
|
Packit |
423ecb |
pat->rules = ret;
|
|
Packit |
423ecb |
} else {
|
|
Packit |
423ecb |
xmlSchematronRulePtr prev = pat->rules;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
while (prev->patnext != NULL)
|
|
Packit |
423ecb |
prev = prev->patnext;
|
|
Packit |
423ecb |
prev->patnext = ret;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
return (ret);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* xmlSchematronFreeRules:
|
|
Packit |
423ecb |
* @rules: a list of rules
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Free a list of rules.
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
static void
|
|
Packit |
423ecb |
xmlSchematronFreeRules(xmlSchematronRulePtr rules) {
|
|
Packit |
423ecb |
xmlSchematronRulePtr next;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
while (rules != NULL) {
|
|
Packit |
423ecb |
next = rules->next;
|
|
Packit |
423ecb |
if (rules->tests)
|
|
Packit |
423ecb |
xmlSchematronFreeTests(rules->tests);
|
|
Packit |
423ecb |
if (rules->context != NULL)
|
|
Packit |
423ecb |
xmlFree(rules->context);
|
|
Packit |
423ecb |
if (rules->pattern)
|
|
Packit |
423ecb |
xmlFreePattern(rules->pattern);
|
|
Packit |
423ecb |
if (rules->report != NULL)
|
|
Packit |
423ecb |
xmlFree(rules->report);
|
|
Packit |
423ecb |
xmlFree(rules);
|
|
Packit |
423ecb |
rules = next;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* xmlSchematronAddPattern:
|
|
Packit |
423ecb |
* @ctxt: the schema parsing context
|
|
Packit |
423ecb |
* @schema: a schema structure
|
|
Packit |
423ecb |
* @node: the node hosting the pattern
|
|
Packit |
423ecb |
* @id: the id or name of the pattern
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Add a pattern to a schematron
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Returns the new pointer or NULL in case of error
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
static xmlSchematronPatternPtr
|
|
Packit |
423ecb |
xmlSchematronAddPattern(xmlSchematronParserCtxtPtr ctxt,
|
|
Packit |
423ecb |
xmlSchematronPtr schema, xmlNodePtr node, xmlChar *name)
|
|
Packit |
423ecb |
{
|
|
Packit |
423ecb |
xmlSchematronPatternPtr ret;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
if ((ctxt == NULL) || (schema == NULL) || (node == NULL) || (name == NULL))
|
|
Packit |
423ecb |
return(NULL);
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
ret = (xmlSchematronPatternPtr) xmlMalloc(sizeof(xmlSchematronPattern));
|
|
Packit |
423ecb |
if (ret == NULL) {
|
|
Packit |
423ecb |
xmlSchematronPErrMemory(ctxt, "allocating schema pattern", node);
|
|
Packit |
423ecb |
return (NULL);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
memset(ret, 0, sizeof(xmlSchematronPattern));
|
|
Packit |
423ecb |
ret->name = name;
|
|
Packit |
423ecb |
ret->next = NULL;
|
|
Packit |
423ecb |
if (schema->patterns == NULL) {
|
|
Packit |
423ecb |
schema->patterns = ret;
|
|
Packit |
423ecb |
} else {
|
|
Packit |
423ecb |
xmlSchematronPatternPtr prev = schema->patterns;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
while (prev->next != NULL)
|
|
Packit |
423ecb |
prev = prev->next;
|
|
Packit |
423ecb |
prev->next = ret;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
return (ret);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* xmlSchematronFreePatterns:
|
|
Packit |
423ecb |
* @patterns: a list of patterns
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Free a list of patterns.
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
static void
|
|
Packit |
423ecb |
xmlSchematronFreePatterns(xmlSchematronPatternPtr patterns) {
|
|
Packit |
423ecb |
xmlSchematronPatternPtr next;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
while (patterns != NULL) {
|
|
Packit |
423ecb |
next = patterns->next;
|
|
Packit |
423ecb |
if (patterns->name != NULL)
|
|
Packit |
423ecb |
xmlFree(patterns->name);
|
|
Packit |
423ecb |
xmlFree(patterns);
|
|
Packit |
423ecb |
patterns = next;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* xmlSchematronNewSchematron:
|
|
Packit |
423ecb |
* @ctxt: a schema validation context
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Allocate a new Schematron structure.
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Returns the newly allocated structure or NULL in case or error
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
static xmlSchematronPtr
|
|
Packit |
423ecb |
xmlSchematronNewSchematron(xmlSchematronParserCtxtPtr ctxt)
|
|
Packit |
423ecb |
{
|
|
Packit |
423ecb |
xmlSchematronPtr ret;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
ret = (xmlSchematronPtr) xmlMalloc(sizeof(xmlSchematron));
|
|
Packit |
423ecb |
if (ret == NULL) {
|
|
Packit |
423ecb |
xmlSchematronPErrMemory(ctxt, "allocating schema", NULL);
|
|
Packit |
423ecb |
return (NULL);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
memset(ret, 0, sizeof(xmlSchematron));
|
|
Packit |
423ecb |
ret->dict = ctxt->dict;
|
|
Packit |
423ecb |
xmlDictReference(ret->dict);
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
return (ret);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* xmlSchematronFree:
|
|
Packit |
423ecb |
* @schema: a schema structure
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Deallocate a Schematron structure.
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
void
|
|
Packit |
423ecb |
xmlSchematronFree(xmlSchematronPtr schema)
|
|
Packit |
423ecb |
{
|
|
Packit |
423ecb |
if (schema == NULL)
|
|
Packit |
423ecb |
return;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
if ((schema->doc != NULL) && (!(schema->preserve)))
|
|
Packit |
423ecb |
xmlFreeDoc(schema->doc);
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
if (schema->namespaces != NULL)
|
|
Packit |
423ecb |
xmlFree((char **) schema->namespaces);
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
xmlSchematronFreeRules(schema->rules);
|
|
Packit |
423ecb |
xmlSchematronFreePatterns(schema->patterns);
|
|
Packit |
423ecb |
xmlDictFree(schema->dict);
|
|
Packit |
423ecb |
xmlFree(schema);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* xmlSchematronNewParserCtxt:
|
|
Packit |
423ecb |
* @URL: the location of the schema
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Create an XML Schematrons parse context for that file/resource expected
|
|
Packit |
423ecb |
* to contain an XML Schematrons file.
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Returns the parser context or NULL in case of error
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
xmlSchematronParserCtxtPtr
|
|
Packit |
423ecb |
xmlSchematronNewParserCtxt(const char *URL)
|
|
Packit |
423ecb |
{
|
|
Packit |
423ecb |
xmlSchematronParserCtxtPtr ret;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
if (URL == NULL)
|
|
Packit |
423ecb |
return (NULL);
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
ret =
|
|
Packit |
423ecb |
(xmlSchematronParserCtxtPtr)
|
|
Packit |
423ecb |
xmlMalloc(sizeof(xmlSchematronParserCtxt));
|
|
Packit |
423ecb |
if (ret == NULL) {
|
|
Packit |
423ecb |
xmlSchematronPErrMemory(NULL, "allocating schema parser context",
|
|
Packit |
423ecb |
NULL);
|
|
Packit |
423ecb |
return (NULL);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
memset(ret, 0, sizeof(xmlSchematronParserCtxt));
|
|
Packit |
423ecb |
ret->type = XML_STRON_CTXT_PARSER;
|
|
Packit |
423ecb |
ret->dict = xmlDictCreate();
|
|
Packit |
423ecb |
ret->URL = xmlDictLookup(ret->dict, (const xmlChar *) URL, -1);
|
|
Packit |
423ecb |
ret->includes = NULL;
|
|
Packit |
423ecb |
ret->xctxt = xmlXPathNewContext(NULL);
|
|
Packit |
423ecb |
if (ret->xctxt == NULL) {
|
|
Packit |
423ecb |
xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context",
|
|
Packit |
423ecb |
NULL);
|
|
Packit |
423ecb |
xmlSchematronFreeParserCtxt(ret);
|
|
Packit |
423ecb |
return (NULL);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
ret->xctxt->flags = XML_XPATH_CHECKNS;
|
|
Packit |
423ecb |
return (ret);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* xmlSchematronNewMemParserCtxt:
|
|
Packit |
423ecb |
* @buffer: a pointer to a char array containing the schemas
|
|
Packit |
423ecb |
* @size: the size of the array
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Create an XML Schematrons parse context for that memory buffer expected
|
|
Packit |
423ecb |
* to contain an XML Schematrons file.
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Returns the parser context or NULL in case of error
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
xmlSchematronParserCtxtPtr
|
|
Packit |
423ecb |
xmlSchematronNewMemParserCtxt(const char *buffer, int size)
|
|
Packit |
423ecb |
{
|
|
Packit |
423ecb |
xmlSchematronParserCtxtPtr ret;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
if ((buffer == NULL) || (size <= 0))
|
|
Packit |
423ecb |
return (NULL);
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
ret =
|
|
Packit |
423ecb |
(xmlSchematronParserCtxtPtr)
|
|
Packit |
423ecb |
xmlMalloc(sizeof(xmlSchematronParserCtxt));
|
|
Packit |
423ecb |
if (ret == NULL) {
|
|
Packit |
423ecb |
xmlSchematronPErrMemory(NULL, "allocating schema parser context",
|
|
Packit |
423ecb |
NULL);
|
|
Packit |
423ecb |
return (NULL);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
memset(ret, 0, sizeof(xmlSchematronParserCtxt));
|
|
Packit |
423ecb |
ret->buffer = buffer;
|
|
Packit |
423ecb |
ret->size = size;
|
|
Packit |
423ecb |
ret->dict = xmlDictCreate();
|
|
Packit |
423ecb |
ret->xctxt = xmlXPathNewContext(NULL);
|
|
Packit |
423ecb |
if (ret->xctxt == NULL) {
|
|
Packit |
423ecb |
xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context",
|
|
Packit |
423ecb |
NULL);
|
|
Packit |
423ecb |
xmlSchematronFreeParserCtxt(ret);
|
|
Packit |
423ecb |
return (NULL);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
return (ret);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* xmlSchematronNewDocParserCtxt:
|
|
Packit |
423ecb |
* @doc: a preparsed document tree
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Create an XML Schematrons parse context for that document.
|
|
Packit |
423ecb |
* NB. The document may be modified during the parsing process.
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Returns the parser context or NULL in case of error
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
xmlSchematronParserCtxtPtr
|
|
Packit |
423ecb |
xmlSchematronNewDocParserCtxt(xmlDocPtr doc)
|
|
Packit |
423ecb |
{
|
|
Packit |
423ecb |
xmlSchematronParserCtxtPtr ret;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
if (doc == NULL)
|
|
Packit |
423ecb |
return (NULL);
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
ret =
|
|
Packit |
423ecb |
(xmlSchematronParserCtxtPtr)
|
|
Packit |
423ecb |
xmlMalloc(sizeof(xmlSchematronParserCtxt));
|
|
Packit |
423ecb |
if (ret == NULL) {
|
|
Packit |
423ecb |
xmlSchematronPErrMemory(NULL, "allocating schema parser context",
|
|
Packit |
423ecb |
NULL);
|
|
Packit |
423ecb |
return (NULL);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
memset(ret, 0, sizeof(xmlSchematronParserCtxt));
|
|
Packit |
423ecb |
ret->doc = doc;
|
|
Packit |
423ecb |
ret->dict = xmlDictCreate();
|
|
Packit |
423ecb |
/* The application has responsibility for the document */
|
|
Packit |
423ecb |
ret->preserve = 1;
|
|
Packit |
423ecb |
ret->xctxt = xmlXPathNewContext(doc);
|
|
Packit |
423ecb |
if (ret->xctxt == NULL) {
|
|
Packit |
423ecb |
xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context",
|
|
Packit |
423ecb |
NULL);
|
|
Packit |
423ecb |
xmlSchematronFreeParserCtxt(ret);
|
|
Packit |
423ecb |
return (NULL);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
return (ret);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* xmlSchematronFreeParserCtxt:
|
|
Packit |
423ecb |
* @ctxt: the schema parser context
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Free the resources associated to the schema parser context
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
void
|
|
Packit |
423ecb |
xmlSchematronFreeParserCtxt(xmlSchematronParserCtxtPtr ctxt)
|
|
Packit |
423ecb |
{
|
|
Packit |
423ecb |
if (ctxt == NULL)
|
|
Packit |
423ecb |
return;
|
|
Packit |
423ecb |
if (ctxt->doc != NULL && !ctxt->preserve)
|
|
Packit |
423ecb |
xmlFreeDoc(ctxt->doc);
|
|
Packit |
423ecb |
if (ctxt->xctxt != NULL) {
|
|
Packit |
423ecb |
xmlXPathFreeContext(ctxt->xctxt);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
if (ctxt->namespaces != NULL)
|
|
Packit |
423ecb |
xmlFree((char **) ctxt->namespaces);
|
|
Packit |
423ecb |
xmlDictFree(ctxt->dict);
|
|
Packit |
423ecb |
xmlFree(ctxt);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
#if 0
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* xmlSchematronPushInclude:
|
|
Packit |
423ecb |
* @ctxt: the schema parser context
|
|
Packit |
423ecb |
* @doc: the included document
|
|
Packit |
423ecb |
* @cur: the current include node
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Add an included document
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
static void
|
|
Packit |
423ecb |
xmlSchematronPushInclude(xmlSchematronParserCtxtPtr ctxt,
|
|
Packit |
423ecb |
xmlDocPtr doc, xmlNodePtr cur)
|
|
Packit |
423ecb |
{
|
|
Packit |
423ecb |
if (ctxt->includes == NULL) {
|
|
Packit |
423ecb |
ctxt->maxIncludes = 10;
|
|
Packit |
423ecb |
ctxt->includes = (xmlNodePtr *)
|
|
Packit |
423ecb |
xmlMalloc(ctxt->maxIncludes * 2 * sizeof(xmlNodePtr));
|
|
Packit |
423ecb |
if (ctxt->includes == NULL) {
|
|
Packit |
423ecb |
xmlSchematronPErrMemory(NULL, "allocating parser includes",
|
|
Packit |
423ecb |
NULL);
|
|
Packit |
423ecb |
return;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
ctxt->nbIncludes = 0;
|
|
Packit |
423ecb |
} else if (ctxt->nbIncludes + 2 >= ctxt->maxIncludes) {
|
|
Packit |
423ecb |
xmlNodePtr *tmp;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
tmp = (xmlNodePtr *)
|
|
Packit |
423ecb |
xmlRealloc(ctxt->includes, ctxt->maxIncludes * 4 *
|
|
Packit |
423ecb |
sizeof(xmlNodePtr));
|
|
Packit |
423ecb |
if (tmp == NULL) {
|
|
Packit |
423ecb |
xmlSchematronPErrMemory(NULL, "allocating parser includes",
|
|
Packit |
423ecb |
NULL);
|
|
Packit |
423ecb |
return;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
ctxt->includes = tmp;
|
|
Packit |
423ecb |
ctxt->maxIncludes *= 2;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
ctxt->includes[2 * ctxt->nbIncludes] = cur;
|
|
Packit |
423ecb |
ctxt->includes[2 * ctxt->nbIncludes + 1] = (xmlNodePtr) doc;
|
|
Packit |
423ecb |
ctxt->nbIncludes++;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* xmlSchematronPopInclude:
|
|
Packit |
423ecb |
* @ctxt: the schema parser context
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Pop an include level. The included document is being freed
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Returns the node immediately following the include or NULL if the
|
|
Packit |
423ecb |
* include list was empty.
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
static xmlNodePtr
|
|
Packit |
423ecb |
xmlSchematronPopInclude(xmlSchematronParserCtxtPtr ctxt)
|
|
Packit |
423ecb |
{
|
|
Packit |
423ecb |
xmlDocPtr doc;
|
|
Packit |
423ecb |
xmlNodePtr ret;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
if (ctxt->nbIncludes <= 0)
|
|
Packit |
423ecb |
return(NULL);
|
|
Packit |
423ecb |
ctxt->nbIncludes--;
|
|
Packit |
423ecb |
doc = (xmlDocPtr) ctxt->includes[2 * ctxt->nbIncludes + 1];
|
|
Packit |
423ecb |
ret = ctxt->includes[2 * ctxt->nbIncludes];
|
|
Packit |
423ecb |
xmlFreeDoc(doc);
|
|
Packit |
423ecb |
if (ret != NULL)
|
|
Packit |
423ecb |
ret = ret->next;
|
|
Packit |
423ecb |
if (ret == NULL)
|
|
Packit |
423ecb |
return(xmlSchematronPopInclude(ctxt));
|
|
Packit |
423ecb |
return(ret);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
#endif
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* xmlSchematronAddNamespace:
|
|
Packit |
423ecb |
* @ctxt: the schema parser context
|
|
Packit |
423ecb |
* @prefix: the namespace prefix
|
|
Packit |
423ecb |
* @ns: the namespace name
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Add a namespace definition in the context
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
static void
|
|
Packit |
423ecb |
xmlSchematronAddNamespace(xmlSchematronParserCtxtPtr ctxt,
|
|
Packit |
423ecb |
const xmlChar *prefix, const xmlChar *ns)
|
|
Packit |
423ecb |
{
|
|
Packit |
423ecb |
if (ctxt->namespaces == NULL) {
|
|
Packit |
423ecb |
ctxt->maxNamespaces = 10;
|
|
Packit |
423ecb |
ctxt->namespaces = (const xmlChar **)
|
|
Packit |
423ecb |
xmlMalloc(ctxt->maxNamespaces * 2 * sizeof(const xmlChar *));
|
|
Packit |
423ecb |
if (ctxt->namespaces == NULL) {
|
|
Packit |
423ecb |
xmlSchematronPErrMemory(NULL, "allocating parser namespaces",
|
|
Packit |
423ecb |
NULL);
|
|
Packit |
423ecb |
return;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
ctxt->nbNamespaces = 0;
|
|
Packit |
423ecb |
} else if (ctxt->nbNamespaces + 2 >= ctxt->maxNamespaces) {
|
|
Packit |
423ecb |
const xmlChar **tmp;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
tmp = (const xmlChar **)
|
|
Packit |
423ecb |
xmlRealloc((xmlChar **) ctxt->namespaces, ctxt->maxNamespaces * 4 *
|
|
Packit |
423ecb |
sizeof(const xmlChar *));
|
|
Packit |
423ecb |
if (tmp == NULL) {
|
|
Packit |
423ecb |
xmlSchematronPErrMemory(NULL, "allocating parser namespaces",
|
|
Packit |
423ecb |
NULL);
|
|
Packit |
423ecb |
return;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
ctxt->namespaces = tmp;
|
|
Packit |
423ecb |
ctxt->maxNamespaces *= 2;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
ctxt->namespaces[2 * ctxt->nbNamespaces] =
|
|
Packit |
423ecb |
xmlDictLookup(ctxt->dict, ns, -1);
|
|
Packit |
423ecb |
ctxt->namespaces[2 * ctxt->nbNamespaces + 1] =
|
|
Packit |
423ecb |
xmlDictLookup(ctxt->dict, prefix, -1);
|
|
Packit |
423ecb |
ctxt->nbNamespaces++;
|
|
Packit |
423ecb |
ctxt->namespaces[2 * ctxt->nbNamespaces] = NULL;
|
|
Packit |
423ecb |
ctxt->namespaces[2 * ctxt->nbNamespaces + 1] = NULL;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* xmlSchematronParseRule:
|
|
Packit |
423ecb |
* @ctxt: a schema validation context
|
|
Packit |
423ecb |
* @rule: the rule node
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* parse a rule element
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
static void
|
|
Packit |
423ecb |
xmlSchematronParseRule(xmlSchematronParserCtxtPtr ctxt,
|
|
Packit |
423ecb |
xmlSchematronPatternPtr pattern,
|
|
Packit |
423ecb |
xmlNodePtr rule)
|
|
Packit |
423ecb |
{
|
|
Packit |
423ecb |
xmlNodePtr cur;
|
|
Packit |
423ecb |
int nbChecks = 0;
|
|
Packit |
423ecb |
xmlChar *test;
|
|
Packit |
423ecb |
xmlChar *context;
|
|
Packit |
423ecb |
xmlChar *report;
|
|
Packit |
423ecb |
xmlSchematronRulePtr ruleptr;
|
|
Packit |
423ecb |
xmlSchematronTestPtr testptr;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
if ((ctxt == NULL) || (rule == NULL)) return;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
context = xmlGetNoNsProp(rule, BAD_CAST "context");
|
|
Packit |
423ecb |
if (context == NULL) {
|
|
Packit |
423ecb |
xmlSchematronPErr(ctxt, rule,
|
|
Packit |
423ecb |
XML_SCHEMAP_NOROOT,
|
|
Packit |
423ecb |
"rule has no context attribute",
|
|
Packit |
423ecb |
NULL, NULL);
|
|
Packit |
423ecb |
return;
|
|
Packit |
423ecb |
} else if (context[0] == 0) {
|
|
Packit |
423ecb |
xmlSchematronPErr(ctxt, rule,
|
|
Packit |
423ecb |
XML_SCHEMAP_NOROOT,
|
|
Packit |
423ecb |
"rule has an empty context attribute",
|
|
Packit |
423ecb |
NULL, NULL);
|
|
Packit |
423ecb |
xmlFree(context);
|
|
Packit |
423ecb |
return;
|
|
Packit |
423ecb |
} else {
|
|
Packit |
423ecb |
ruleptr = xmlSchematronAddRule(ctxt, ctxt->schema, pattern,
|
|
Packit |
423ecb |
rule, context, NULL);
|
|
Packit |
423ecb |
if (ruleptr == NULL) {
|
|
Packit |
423ecb |
xmlFree(context);
|
|
Packit |
423ecb |
return;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
cur = rule->children;
|
|
Packit |
423ecb |
NEXT_SCHEMATRON(cur);
|
|
Packit |
423ecb |
while (cur != NULL) {
|
|
Packit |
423ecb |
if (IS_SCHEMATRON(cur, "assert")) {
|
|
Packit |
423ecb |
nbChecks++;
|
|
Packit |
423ecb |
test = xmlGetNoNsProp(cur, BAD_CAST "test");
|
|
Packit |
423ecb |
if (test == NULL) {
|
|
Packit |
423ecb |
xmlSchematronPErr(ctxt, cur,
|
|
Packit |
423ecb |
XML_SCHEMAP_NOROOT,
|
|
Packit |
423ecb |
"assert has no test attribute",
|
|
Packit |
423ecb |
NULL, NULL);
|
|
Packit |
423ecb |
} else if (test[0] == 0) {
|
|
Packit |
423ecb |
xmlSchematronPErr(ctxt, cur,
|
|
Packit |
423ecb |
XML_SCHEMAP_NOROOT,
|
|
Packit |
423ecb |
"assert has an empty test attribute",
|
|
Packit |
423ecb |
NULL, NULL);
|
|
Packit |
423ecb |
xmlFree(test);
|
|
Packit |
423ecb |
} else {
|
|
Packit |
423ecb |
/* TODO will need dynamic processing instead */
|
|
Packit |
423ecb |
report = xmlNodeGetContent(cur);
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
testptr = xmlSchematronAddTest(ctxt, XML_SCHEMATRON_ASSERT,
|
|
Packit |
423ecb |
ruleptr, cur, test, report);
|
|
Packit |
423ecb |
if (testptr == NULL)
|
|
Packit |
423ecb |
xmlFree(test);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
} else if (IS_SCHEMATRON(cur, "report")) {
|
|
Packit |
423ecb |
nbChecks++;
|
|
Packit |
423ecb |
test = xmlGetNoNsProp(cur, BAD_CAST "test");
|
|
Packit |
423ecb |
if (test == NULL) {
|
|
Packit |
423ecb |
xmlSchematronPErr(ctxt, cur,
|
|
Packit |
423ecb |
XML_SCHEMAP_NOROOT,
|
|
Packit |
423ecb |
"assert has no test attribute",
|
|
Packit |
423ecb |
NULL, NULL);
|
|
Packit |
423ecb |
} else if (test[0] == 0) {
|
|
Packit |
423ecb |
xmlSchematronPErr(ctxt, cur,
|
|
Packit |
423ecb |
XML_SCHEMAP_NOROOT,
|
|
Packit |
423ecb |
"assert has an empty test attribute",
|
|
Packit |
423ecb |
NULL, NULL);
|
|
Packit |
423ecb |
xmlFree(test);
|
|
Packit |
423ecb |
} else {
|
|
Packit |
423ecb |
/* TODO will need dynamic processing instead */
|
|
Packit |
423ecb |
report = xmlNodeGetContent(cur);
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
testptr = xmlSchematronAddTest(ctxt, XML_SCHEMATRON_REPORT,
|
|
Packit |
423ecb |
ruleptr, cur, test, report);
|
|
Packit |
423ecb |
if (testptr == NULL)
|
|
Packit |
423ecb |
xmlFree(test);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
} else {
|
|
Packit |
423ecb |
xmlSchematronPErr(ctxt, cur,
|
|
Packit |
423ecb |
XML_SCHEMAP_NOROOT,
|
|
Packit |
423ecb |
"Expecting an assert or a report element instead of %s",
|
|
Packit |
423ecb |
cur->name, NULL);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
cur = cur->next;
|
|
Packit |
423ecb |
NEXT_SCHEMATRON(cur);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
if (nbChecks == 0) {
|
|
Packit |
423ecb |
xmlSchematronPErr(ctxt, rule,
|
|
Packit |
423ecb |
XML_SCHEMAP_NOROOT,
|
|
Packit |
423ecb |
"rule has no assert nor report element", NULL, NULL);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* xmlSchematronParsePattern:
|
|
Packit |
423ecb |
* @ctxt: a schema validation context
|
|
Packit |
423ecb |
* @pat: the pattern node
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* parse a pattern element
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
static void
|
|
Packit |
423ecb |
xmlSchematronParsePattern(xmlSchematronParserCtxtPtr ctxt, xmlNodePtr pat)
|
|
Packit |
423ecb |
{
|
|
Packit |
423ecb |
xmlNodePtr cur;
|
|
Packit |
423ecb |
xmlSchematronPatternPtr pattern;
|
|
Packit |
423ecb |
int nbRules = 0;
|
|
Packit |
423ecb |
xmlChar *id;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
if ((ctxt == NULL) || (pat == NULL)) return;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
id = xmlGetNoNsProp(pat, BAD_CAST "id");
|
|
Packit |
423ecb |
if (id == NULL) {
|
|
Packit |
423ecb |
id = xmlGetNoNsProp(pat, BAD_CAST "name");
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
pattern = xmlSchematronAddPattern(ctxt, ctxt->schema, pat, id);
|
|
Packit |
423ecb |
if (pattern == NULL) {
|
|
Packit |
423ecb |
if (id != NULL)
|
|
Packit |
423ecb |
xmlFree(id);
|
|
Packit |
423ecb |
return;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
cur = pat->children;
|
|
Packit |
423ecb |
NEXT_SCHEMATRON(cur);
|
|
Packit |
423ecb |
while (cur != NULL) {
|
|
Packit |
423ecb |
if (IS_SCHEMATRON(cur, "rule")) {
|
|
Packit |
423ecb |
xmlSchematronParseRule(ctxt, pattern, cur);
|
|
Packit |
423ecb |
nbRules++;
|
|
Packit |
423ecb |
} else {
|
|
Packit |
423ecb |
xmlSchematronPErr(ctxt, cur,
|
|
Packit |
423ecb |
XML_SCHEMAP_NOROOT,
|
|
Packit |
423ecb |
"Expecting a rule element instead of %s", cur->name, NULL);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
cur = cur->next;
|
|
Packit |
423ecb |
NEXT_SCHEMATRON(cur);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
if (nbRules == 0) {
|
|
Packit |
423ecb |
xmlSchematronPErr(ctxt, pat,
|
|
Packit |
423ecb |
XML_SCHEMAP_NOROOT,
|
|
Packit |
423ecb |
"Pattern has no rule element", NULL, NULL);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
#if 0
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* xmlSchematronLoadInclude:
|
|
Packit |
423ecb |
* @ctxt: a schema validation context
|
|
Packit |
423ecb |
* @cur: the include element
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Load the include document, Push the current pointer
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Returns the updated node pointer
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
static xmlNodePtr
|
|
Packit |
423ecb |
xmlSchematronLoadInclude(xmlSchematronParserCtxtPtr ctxt, xmlNodePtr cur)
|
|
Packit |
423ecb |
{
|
|
Packit |
423ecb |
xmlNodePtr ret = NULL;
|
|
Packit |
423ecb |
xmlDocPtr doc = NULL;
|
|
Packit |
423ecb |
xmlChar *href = NULL;
|
|
Packit |
423ecb |
xmlChar *base = NULL;
|
|
Packit |
423ecb |
xmlChar *URI = NULL;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
if ((ctxt == NULL) || (cur == NULL))
|
|
Packit |
423ecb |
return(NULL);
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
href = xmlGetNoNsProp(cur, BAD_CAST "href");
|
|
Packit |
423ecb |
if (href == NULL) {
|
|
Packit |
423ecb |
xmlSchematronPErr(ctxt, cur,
|
|
Packit |
423ecb |
XML_SCHEMAP_NOROOT,
|
|
Packit |
423ecb |
"Include has no href attribute", NULL, NULL);
|
|
Packit |
423ecb |
return(cur->next);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/* do the URI base composition, load and find the root */
|
|
Packit |
423ecb |
base = xmlNodeGetBase(cur->doc, cur);
|
|
Packit |
423ecb |
URI = xmlBuildURI(href, base);
|
|
Packit |
423ecb |
doc = xmlReadFile((const char *) URI, NULL, SCHEMATRON_PARSE_OPTIONS);
|
|
Packit |
423ecb |
if (doc == NULL) {
|
|
Packit |
423ecb |
xmlSchematronPErr(ctxt, cur,
|
|
Packit |
423ecb |
XML_SCHEMAP_FAILED_LOAD,
|
|
Packit |
423ecb |
"could not load include '%s'.\n",
|
|
Packit |
423ecb |
URI, NULL);
|
|
Packit |
423ecb |
goto done;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
ret = xmlDocGetRootElement(doc);
|
|
Packit |
423ecb |
if (ret == NULL) {
|
|
Packit |
423ecb |
xmlSchematronPErr(ctxt, cur,
|
|
Packit |
423ecb |
XML_SCHEMAP_FAILED_LOAD,
|
|
Packit |
423ecb |
"could not find root from include '%s'.\n",
|
|
Packit |
423ecb |
URI, NULL);
|
|
Packit |
423ecb |
goto done;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/* Success, push the include for rollback on exit */
|
|
Packit |
423ecb |
xmlSchematronPushInclude(ctxt, doc, cur);
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
done:
|
|
Packit |
423ecb |
if (ret == NULL) {
|
|
Packit |
423ecb |
if (doc != NULL)
|
|
Packit |
423ecb |
xmlFreeDoc(doc);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
xmlFree(href);
|
|
Packit |
423ecb |
if (base != NULL)
|
|
Packit |
423ecb |
xmlFree(base);
|
|
Packit |
423ecb |
if (URI != NULL)
|
|
Packit |
423ecb |
xmlFree(URI);
|
|
Packit |
423ecb |
return(ret);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
#endif
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* xmlSchematronParse:
|
|
Packit |
423ecb |
* @ctxt: a schema validation context
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* parse a schema definition resource and build an internal
|
|
Packit |
423ecb |
* XML Shema struture which can be used to validate instances.
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Returns the internal XML Schematron structure built from the resource or
|
|
Packit |
423ecb |
* NULL in case of error
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
xmlSchematronPtr
|
|
Packit |
423ecb |
xmlSchematronParse(xmlSchematronParserCtxtPtr ctxt)
|
|
Packit |
423ecb |
{
|
|
Packit |
423ecb |
xmlSchematronPtr ret = NULL;
|
|
Packit |
423ecb |
xmlDocPtr doc;
|
|
Packit |
423ecb |
xmlNodePtr root, cur;
|
|
Packit |
423ecb |
int preserve = 0;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
if (ctxt == NULL)
|
|
Packit |
423ecb |
return (NULL);
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
ctxt->nberrors = 0;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/*
|
|
Packit |
423ecb |
* First step is to parse the input document into an DOM/Infoset
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
if (ctxt->URL != NULL) {
|
|
Packit |
423ecb |
doc = xmlReadFile((const char *) ctxt->URL, NULL,
|
|
Packit |
423ecb |
SCHEMATRON_PARSE_OPTIONS);
|
|
Packit |
423ecb |
if (doc == NULL) {
|
|
Packit |
423ecb |
xmlSchematronPErr(ctxt, NULL,
|
|
Packit |
423ecb |
XML_SCHEMAP_FAILED_LOAD,
|
|
Packit |
423ecb |
"xmlSchematronParse: could not load '%s'.\n",
|
|
Packit |
423ecb |
ctxt->URL, NULL);
|
|
Packit |
423ecb |
return (NULL);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
ctxt->preserve = 0;
|
|
Packit |
423ecb |
} else if (ctxt->buffer != NULL) {
|
|
Packit |
423ecb |
doc = xmlReadMemory(ctxt->buffer, ctxt->size, NULL, NULL,
|
|
Packit |
423ecb |
SCHEMATRON_PARSE_OPTIONS);
|
|
Packit |
423ecb |
if (doc == NULL) {
|
|
Packit |
423ecb |
xmlSchematronPErr(ctxt, NULL,
|
|
Packit |
423ecb |
XML_SCHEMAP_FAILED_PARSE,
|
|
Packit |
423ecb |
"xmlSchematronParse: could not parse.\n",
|
|
Packit |
423ecb |
NULL, NULL);
|
|
Packit |
423ecb |
return (NULL);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
|
|
Packit |
423ecb |
ctxt->URL = xmlDictLookup(ctxt->dict, BAD_CAST "in_memory_buffer", -1);
|
|
Packit |
423ecb |
ctxt->preserve = 0;
|
|
Packit |
423ecb |
} else if (ctxt->doc != NULL) {
|
|
Packit |
423ecb |
doc = ctxt->doc;
|
|
Packit |
423ecb |
preserve = 1;
|
|
Packit |
423ecb |
ctxt->preserve = 1;
|
|
Packit |
423ecb |
} else {
|
|
Packit |
423ecb |
xmlSchematronPErr(ctxt, NULL,
|
|
Packit |
423ecb |
XML_SCHEMAP_NOTHING_TO_PARSE,
|
|
Packit |
423ecb |
"xmlSchematronParse: could not parse.\n",
|
|
Packit |
423ecb |
NULL, NULL);
|
|
Packit |
423ecb |
return (NULL);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/*
|
|
Packit |
423ecb |
* Then extract the root and Schematron parse it
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
root = xmlDocGetRootElement(doc);
|
|
Packit |
423ecb |
if (root == NULL) {
|
|
Packit |
423ecb |
xmlSchematronPErr(ctxt, (xmlNodePtr) doc,
|
|
Packit |
423ecb |
XML_SCHEMAP_NOROOT,
|
|
Packit |
423ecb |
"The schema has no document element.\n", NULL, NULL);
|
|
Packit |
423ecb |
if (!preserve) {
|
|
Packit |
423ecb |
xmlFreeDoc(doc);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
return (NULL);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
if (!IS_SCHEMATRON(root, "schema")) {
|
|
Packit |
423ecb |
xmlSchematronPErr(ctxt, root,
|
|
Packit |
423ecb |
XML_SCHEMAP_NOROOT,
|
|
Packit |
423ecb |
"The XML document '%s' is not a XML schematron document",
|
|
Packit |
423ecb |
ctxt->URL, NULL);
|
|
Packit |
423ecb |
goto exit;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
ret = xmlSchematronNewSchematron(ctxt);
|
|
Packit |
423ecb |
if (ret == NULL)
|
|
Packit |
423ecb |
goto exit;
|
|
Packit |
423ecb |
ctxt->schema = ret;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/*
|
|
Packit |
423ecb |
* scan the schema elements
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
cur = root->children;
|
|
Packit |
423ecb |
NEXT_SCHEMATRON(cur);
|
|
Packit |
423ecb |
if (IS_SCHEMATRON(cur, "title")) {
|
|
Packit |
423ecb |
xmlChar *title = xmlNodeGetContent(cur);
|
|
Packit |
423ecb |
if (title != NULL) {
|
|
Packit |
423ecb |
ret->title = xmlDictLookup(ret->dict, title, -1);
|
|
Packit |
423ecb |
xmlFree(title);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
cur = cur->next;
|
|
Packit |
423ecb |
NEXT_SCHEMATRON(cur);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
while (IS_SCHEMATRON(cur, "ns")) {
|
|
Packit |
423ecb |
xmlChar *prefix = xmlGetNoNsProp(cur, BAD_CAST "prefix");
|
|
Packit |
423ecb |
xmlChar *uri = xmlGetNoNsProp(cur, BAD_CAST "uri");
|
|
Packit |
423ecb |
if ((uri == NULL) || (uri[0] == 0)) {
|
|
Packit |
423ecb |
xmlSchematronPErr(ctxt, cur,
|
|
Packit |
423ecb |
XML_SCHEMAP_NOROOT,
|
|
Packit |
423ecb |
"ns element has no uri", NULL, NULL);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
if ((prefix == NULL) || (prefix[0] == 0)) {
|
|
Packit |
423ecb |
xmlSchematronPErr(ctxt, cur,
|
|
Packit |
423ecb |
XML_SCHEMAP_NOROOT,
|
|
Packit |
423ecb |
"ns element has no prefix", NULL, NULL);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
if ((prefix) && (uri)) {
|
|
Packit |
423ecb |
xmlXPathRegisterNs(ctxt->xctxt, prefix, uri);
|
|
Packit |
423ecb |
xmlSchematronAddNamespace(ctxt, prefix, uri);
|
|
Packit |
423ecb |
ret->nbNs++;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
if (uri)
|
|
Packit |
423ecb |
xmlFree(uri);
|
|
Packit |
423ecb |
if (prefix)
|
|
Packit |
423ecb |
xmlFree(prefix);
|
|
Packit |
423ecb |
cur = cur->next;
|
|
Packit |
423ecb |
NEXT_SCHEMATRON(cur);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
while (cur != NULL) {
|
|
Packit |
423ecb |
if (IS_SCHEMATRON(cur, "pattern")) {
|
|
Packit |
423ecb |
xmlSchematronParsePattern(ctxt, cur);
|
|
Packit |
423ecb |
ret->nbPattern++;
|
|
Packit |
423ecb |
} else {
|
|
Packit |
423ecb |
xmlSchematronPErr(ctxt, cur,
|
|
Packit |
423ecb |
XML_SCHEMAP_NOROOT,
|
|
Packit |
423ecb |
"Expecting a pattern element instead of %s", cur->name, NULL);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
cur = cur->next;
|
|
Packit |
423ecb |
NEXT_SCHEMATRON(cur);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
if (ret->nbPattern == 0) {
|
|
Packit |
423ecb |
xmlSchematronPErr(ctxt, root,
|
|
Packit |
423ecb |
XML_SCHEMAP_NOROOT,
|
|
Packit |
423ecb |
"The schematron document '%s' has no pattern",
|
|
Packit |
423ecb |
ctxt->URL, NULL);
|
|
Packit |
423ecb |
goto exit;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
/* the original document must be kept for reporting */
|
|
Packit |
423ecb |
ret->doc = doc;
|
|
Packit |
423ecb |
if (preserve) {
|
|
Packit |
423ecb |
ret->preserve = 1;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
preserve = 1;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
exit:
|
|
Packit |
423ecb |
if (!preserve) {
|
|
Packit |
423ecb |
xmlFreeDoc(doc);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
if (ret != NULL) {
|
|
Packit |
423ecb |
if (ctxt->nberrors != 0) {
|
|
Packit |
423ecb |
xmlSchematronFree(ret);
|
|
Packit |
423ecb |
ret = NULL;
|
|
Packit |
423ecb |
} else {
|
|
Packit |
423ecb |
ret->namespaces = ctxt->namespaces;
|
|
Packit |
423ecb |
ret->nbNamespaces = ctxt->nbNamespaces;
|
|
Packit |
423ecb |
ctxt->namespaces = NULL;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
return (ret);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/************************************************************************
|
|
Packit |
423ecb |
* *
|
|
Packit |
423ecb |
* Schematrontron Reports handler *
|
|
Packit |
423ecb |
* *
|
|
Packit |
423ecb |
************************************************************************/
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
static xmlNodePtr
|
|
Packit |
423ecb |
xmlSchematronGetNode(xmlSchematronValidCtxtPtr ctxt,
|
|
Packit |
423ecb |
xmlNodePtr cur, const xmlChar *xpath) {
|
|
Packit |
423ecb |
xmlNodePtr node = NULL;
|
|
Packit |
423ecb |
xmlXPathObjectPtr ret;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
if ((ctxt == NULL) || (cur == NULL) || (xpath == NULL))
|
|
Packit |
423ecb |
return(NULL);
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
ctxt->xctxt->doc = cur->doc;
|
|
Packit |
423ecb |
ctxt->xctxt->node = cur;
|
|
Packit |
423ecb |
ret = xmlXPathEval(xpath, ctxt->xctxt);
|
|
Packit |
423ecb |
if (ret == NULL)
|
|
Packit |
423ecb |
return(NULL);
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
if ((ret->type == XPATH_NODESET) &&
|
|
Packit |
423ecb |
(ret->nodesetval != NULL) && (ret->nodesetval->nodeNr > 0))
|
|
Packit |
423ecb |
node = ret->nodesetval->nodeTab[0];
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
xmlXPathFreeObject(ret);
|
|
Packit |
423ecb |
return(node);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* xmlSchematronReportOutput:
|
|
Packit |
423ecb |
* @ctxt: the validation context
|
|
Packit |
423ecb |
* @cur: the current node tested
|
|
Packit |
423ecb |
* @msg: the message output
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Output part of the report to whatever channel the user selected
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
static void
|
|
Packit |
423ecb |
xmlSchematronReportOutput(xmlSchematronValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
|
|
Packit |
423ecb |
xmlNodePtr cur ATTRIBUTE_UNUSED,
|
|
Packit |
423ecb |
const char *msg) {
|
|
Packit |
423ecb |
/* TODO */
|
|
Packit |
423ecb |
fprintf(stderr, "%s", msg);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* xmlSchematronFormatReport:
|
|
Packit |
423ecb |
* @ctxt: the validation context
|
|
Packit |
423ecb |
* @test: the test node
|
|
Packit |
423ecb |
* @cur: the current node tested
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Build the string being reported to the user.
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Returns a report string or NULL in case of error. The string needs
|
|
Packit |
423ecb |
* to be deallocated by teh caller
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
static xmlChar *
|
|
Packit |
423ecb |
xmlSchematronFormatReport(xmlSchematronValidCtxtPtr ctxt,
|
|
Packit |
423ecb |
xmlNodePtr test, xmlNodePtr cur) {
|
|
Packit |
423ecb |
xmlChar *ret = NULL;
|
|
Packit |
423ecb |
xmlNodePtr child, node;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
if ((test == NULL) || (cur == NULL))
|
|
Packit |
423ecb |
return(ret);
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
child = test->children;
|
|
Packit |
423ecb |
while (child != NULL) {
|
|
Packit |
423ecb |
if ((child->type == XML_TEXT_NODE) ||
|
|
Packit |
423ecb |
(child->type == XML_CDATA_SECTION_NODE))
|
|
Packit |
423ecb |
ret = xmlStrcat(ret, child->content);
|
|
Packit |
423ecb |
else if (IS_SCHEMATRON(child, "name")) {
|
|
Packit |
423ecb |
xmlChar *path;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
path = xmlGetNoNsProp(child, BAD_CAST "path");
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
node = cur;
|
|
Packit |
423ecb |
if (path != NULL) {
|
|
Packit |
423ecb |
node = xmlSchematronGetNode(ctxt, cur, path);
|
|
Packit |
423ecb |
if (node == NULL)
|
|
Packit |
423ecb |
node = cur;
|
|
Packit |
423ecb |
xmlFree(path);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
if ((node->ns == NULL) || (node->ns->prefix == NULL))
|
|
Packit |
423ecb |
ret = xmlStrcat(ret, node->name);
|
|
Packit |
423ecb |
else {
|
|
Packit |
423ecb |
ret = xmlStrcat(ret, node->ns->prefix);
|
|
Packit |
423ecb |
ret = xmlStrcat(ret, BAD_CAST ":");
|
|
Packit |
423ecb |
ret = xmlStrcat(ret, node->name);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
} else {
|
|
Packit |
423ecb |
child = child->next;
|
|
Packit |
423ecb |
continue;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/*
|
|
Packit |
423ecb |
* remove superfluous \n
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
if (ret != NULL) {
|
|
Packit |
423ecb |
int len = xmlStrlen(ret);
|
|
Packit |
423ecb |
xmlChar c;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
if (len > 0) {
|
|
Packit |
423ecb |
c = ret[len - 1];
|
|
Packit |
423ecb |
if ((c == ' ') || (c == '\n') || (c == '\r') || (c == '\t')) {
|
|
Packit |
423ecb |
while ((c == ' ') || (c == '\n') ||
|
|
Packit |
423ecb |
(c == '\r') || (c == '\t')) {
|
|
Packit |
423ecb |
len--;
|
|
Packit |
423ecb |
if (len == 0)
|
|
Packit |
423ecb |
break;
|
|
Packit |
423ecb |
c = ret[len - 1];
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
ret[len] = ' ';
|
|
Packit |
423ecb |
ret[len + 1] = 0;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
child = child->next;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
return(ret);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* xmlSchematronReportSuccess:
|
|
Packit |
423ecb |
* @ctxt: the validation context
|
|
Packit |
423ecb |
* @test: the compiled test
|
|
Packit |
423ecb |
* @cur: the current node tested
|
|
Packit |
423ecb |
* @success: boolean value for the result
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* called from the validation engine when an assert or report test have
|
|
Packit |
423ecb |
* been done.
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
static void
|
|
Packit |
423ecb |
xmlSchematronReportSuccess(xmlSchematronValidCtxtPtr ctxt,
|
|
Packit |
423ecb |
xmlSchematronTestPtr test, xmlNodePtr cur, xmlSchematronPatternPtr pattern, int success) {
|
|
Packit |
423ecb |
if ((ctxt == NULL) || (cur == NULL) || (test == NULL))
|
|
Packit |
423ecb |
return;
|
|
Packit |
423ecb |
/* if quiet and not SVRL report only failures */
|
|
Packit |
423ecb |
if ((ctxt->flags & XML_SCHEMATRON_OUT_QUIET) &&
|
|
Packit |
423ecb |
((ctxt->flags & XML_SCHEMATRON_OUT_XML) == 0) &&
|
|
Packit |
423ecb |
(test->type == XML_SCHEMATRON_REPORT))
|
|
Packit |
423ecb |
return;
|
|
Packit |
423ecb |
if (ctxt->flags & XML_SCHEMATRON_OUT_XML) {
|
|
Packit |
423ecb |
TODO
|
|
Packit |
423ecb |
} else {
|
|
Packit |
423ecb |
xmlChar *path;
|
|
Packit |
423ecb |
char msg[1000];
|
|
Packit |
423ecb |
long line;
|
|
Packit |
423ecb |
const xmlChar *report = NULL;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
if (((test->type == XML_SCHEMATRON_REPORT) & (!success)) ||
|
|
Packit |
423ecb |
((test->type == XML_SCHEMATRON_ASSERT) & (success)))
|
|
Packit |
423ecb |
return;
|
|
Packit |
423ecb |
line = xmlGetLineNo(cur);
|
|
Packit |
423ecb |
path = xmlGetNodePath(cur);
|
|
Packit |
423ecb |
if (path == NULL)
|
|
Packit |
423ecb |
path = (xmlChar *) cur->name;
|
|
Packit |
423ecb |
#if 0
|
|
Packit |
423ecb |
if ((test->report != NULL) && (test->report[0] != 0))
|
|
Packit |
423ecb |
report = test->report;
|
|
Packit |
423ecb |
#endif
|
|
Packit |
423ecb |
if (test->node != NULL)
|
|
Packit |
423ecb |
report = xmlSchematronFormatReport(ctxt, test->node, cur);
|
|
Packit |
423ecb |
if (report == NULL) {
|
|
Packit |
423ecb |
if (test->type == XML_SCHEMATRON_ASSERT) {
|
|
Packit |
423ecb |
report = xmlStrdup((const xmlChar *) "node failed assert");
|
|
Packit |
423ecb |
} else {
|
|
Packit |
423ecb |
report = xmlStrdup((const xmlChar *) "node failed report");
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
snprintf(msg, 999, "%s line %ld: %s\n", (const char *) path,
|
|
Packit |
423ecb |
line, (const char *) report);
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
if (ctxt->flags & XML_SCHEMATRON_OUT_ERROR) {
|
|
Packit |
423ecb |
xmlStructuredErrorFunc schannel = NULL;
|
|
Packit |
423ecb |
xmlGenericErrorFunc channel = NULL;
|
|
Packit |
423ecb |
void *data = NULL;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
if (ctxt != NULL) {
|
|
Packit |
423ecb |
if (ctxt->serror != NULL)
|
|
Packit |
423ecb |
schannel = ctxt->serror;
|
|
Packit |
423ecb |
else
|
|
Packit |
423ecb |
channel = ctxt->error;
|
|
Packit |
423ecb |
data = ctxt->userData;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
__xmlRaiseError(schannel, channel, data,
|
|
Packit |
423ecb |
NULL, cur, XML_FROM_SCHEMATRONV,
|
|
Packit |
423ecb |
(test->type == XML_SCHEMATRON_ASSERT)?XML_SCHEMATRONV_ASSERT:XML_SCHEMATRONV_REPORT,
|
|
Packit |
423ecb |
XML_ERR_ERROR, NULL, line,
|
|
Packit |
423ecb |
(pattern == NULL)?NULL:((const char *) pattern->name),
|
|
Packit |
423ecb |
(const char *) path,
|
|
Packit |
423ecb |
(const char *) report, 0, 0,
|
|
Packit |
423ecb |
"%s", msg);
|
|
Packit |
423ecb |
} else {
|
|
Packit |
423ecb |
xmlSchematronReportOutput(ctxt, cur, &msg[0]);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
xmlFree((char *) report);
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
if ((path != NULL) && (path != (xmlChar *) cur->name))
|
|
Packit |
423ecb |
xmlFree(path);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* xmlSchematronReportPattern:
|
|
Packit |
423ecb |
* @ctxt: the validation context
|
|
Packit |
423ecb |
* @pattern: the current pattern
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* called from the validation engine when starting to check a pattern
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
static void
|
|
Packit |
423ecb |
xmlSchematronReportPattern(xmlSchematronValidCtxtPtr ctxt,
|
|
Packit |
423ecb |
xmlSchematronPatternPtr pattern) {
|
|
Packit |
423ecb |
if ((ctxt == NULL) || (pattern == NULL))
|
|
Packit |
423ecb |
return;
|
|
Packit |
423ecb |
if ((ctxt->flags & XML_SCHEMATRON_OUT_QUIET) || (ctxt->flags & XML_SCHEMATRON_OUT_ERROR)) /* Error gives pattern name as part of error */
|
|
Packit |
423ecb |
return;
|
|
Packit |
423ecb |
if (ctxt->flags & XML_SCHEMATRON_OUT_XML) {
|
|
Packit |
423ecb |
TODO
|
|
Packit |
423ecb |
} else {
|
|
Packit |
423ecb |
char msg[1000];
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
if (pattern->name == NULL)
|
|
Packit |
423ecb |
return;
|
|
Packit |
423ecb |
snprintf(msg, 999, "Pattern: %s\n", (const char *) pattern->name);
|
|
Packit |
423ecb |
xmlSchematronReportOutput(ctxt, NULL, &msg[0]);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/************************************************************************
|
|
Packit |
423ecb |
* *
|
|
Packit |
423ecb |
* Validation against a Schematrontron *
|
|
Packit |
423ecb |
* *
|
|
Packit |
423ecb |
************************************************************************/
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* xmlSchematronSetValidStructuredErrors:
|
|
Packit |
423ecb |
* @ctxt: a Schematron validation context
|
|
Packit |
423ecb |
* @serror: the structured error function
|
|
Packit |
423ecb |
* @ctx: the functions context
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Set the structured error callback
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
void
|
|
Packit |
423ecb |
xmlSchematronSetValidStructuredErrors(xmlSchematronValidCtxtPtr ctxt,
|
|
Packit |
423ecb |
xmlStructuredErrorFunc serror, void *ctx)
|
|
Packit |
423ecb |
{
|
|
Packit |
423ecb |
if (ctxt == NULL)
|
|
Packit |
423ecb |
return;
|
|
Packit |
423ecb |
ctxt->serror = serror;
|
|
Packit |
423ecb |
ctxt->error = NULL;
|
|
Packit |
423ecb |
ctxt->warning = NULL;
|
|
Packit |
423ecb |
ctxt->userData = ctx;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* xmlSchematronNewValidCtxt:
|
|
Packit |
423ecb |
* @schema: a precompiled XML Schematrons
|
|
Packit |
423ecb |
* @options: a set of xmlSchematronValidOptions
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Create an XML Schematrons validation context based on the given schema.
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Returns the validation context or NULL in case of error
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
xmlSchematronValidCtxtPtr
|
|
Packit |
423ecb |
xmlSchematronNewValidCtxt(xmlSchematronPtr schema, int options)
|
|
Packit |
423ecb |
{
|
|
Packit |
423ecb |
int i;
|
|
Packit |
423ecb |
xmlSchematronValidCtxtPtr ret;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
ret = (xmlSchematronValidCtxtPtr) xmlMalloc(sizeof(xmlSchematronValidCtxt));
|
|
Packit |
423ecb |
if (ret == NULL) {
|
|
Packit |
423ecb |
xmlSchematronVErrMemory(NULL, "allocating validation context",
|
|
Packit |
423ecb |
NULL);
|
|
Packit |
423ecb |
return (NULL);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
memset(ret, 0, sizeof(xmlSchematronValidCtxt));
|
|
Packit |
423ecb |
ret->type = XML_STRON_CTXT_VALIDATOR;
|
|
Packit |
423ecb |
ret->schema = schema;
|
|
Packit |
423ecb |
ret->xctxt = xmlXPathNewContext(NULL);
|
|
Packit |
423ecb |
ret->flags = options;
|
|
Packit |
423ecb |
if (ret->xctxt == NULL) {
|
|
Packit |
423ecb |
xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context",
|
|
Packit |
423ecb |
NULL);
|
|
Packit |
423ecb |
xmlSchematronFreeValidCtxt(ret);
|
|
Packit |
423ecb |
return (NULL);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
for (i = 0;i < schema->nbNamespaces;i++) {
|
|
Packit |
423ecb |
if ((schema->namespaces[2 * i] == NULL) ||
|
|
Packit |
423ecb |
(schema->namespaces[2 * i + 1] == NULL))
|
|
Packit |
423ecb |
break;
|
|
Packit |
423ecb |
xmlXPathRegisterNs(ret->xctxt, schema->namespaces[2 * i + 1],
|
|
Packit |
423ecb |
schema->namespaces[2 * i]);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
return (ret);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* xmlSchematronFreeValidCtxt:
|
|
Packit |
423ecb |
* @ctxt: the schema validation context
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Free the resources associated to the schema validation context
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
void
|
|
Packit |
423ecb |
xmlSchematronFreeValidCtxt(xmlSchematronValidCtxtPtr ctxt)
|
|
Packit |
423ecb |
{
|
|
Packit |
423ecb |
if (ctxt == NULL)
|
|
Packit |
423ecb |
return;
|
|
Packit |
423ecb |
if (ctxt->xctxt != NULL)
|
|
Packit |
423ecb |
xmlXPathFreeContext(ctxt->xctxt);
|
|
Packit |
423ecb |
if (ctxt->dict != NULL)
|
|
Packit |
423ecb |
xmlDictFree(ctxt->dict);
|
|
Packit |
423ecb |
xmlFree(ctxt);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
static xmlNodePtr
|
|
Packit |
423ecb |
xmlSchematronNextNode(xmlNodePtr cur) {
|
|
Packit |
423ecb |
if (cur->children != NULL) {
|
|
Packit |
423ecb |
/*
|
|
Packit |
423ecb |
* Do not descend on entities declarations
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
if (cur->children->type != XML_ENTITY_DECL) {
|
|
Packit |
423ecb |
cur = cur->children;
|
|
Packit |
423ecb |
/*
|
|
Packit |
423ecb |
* Skip DTDs
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
if (cur->type != XML_DTD_NODE)
|
|
Packit |
423ecb |
return(cur);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
while (cur->next != NULL) {
|
|
Packit |
423ecb |
cur = cur->next;
|
|
Packit |
423ecb |
if ((cur->type != XML_ENTITY_DECL) &&
|
|
Packit |
423ecb |
(cur->type != XML_DTD_NODE))
|
|
Packit |
423ecb |
return(cur);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
do {
|
|
Packit |
423ecb |
cur = cur->parent;
|
|
Packit |
423ecb |
if (cur == NULL) break;
|
|
Packit |
423ecb |
if (cur->type == XML_DOCUMENT_NODE) return(NULL);
|
|
Packit |
423ecb |
if (cur->next != NULL) {
|
|
Packit |
423ecb |
cur = cur->next;
|
|
Packit |
423ecb |
return(cur);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
} while (cur != NULL);
|
|
Packit |
423ecb |
return(cur);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* xmlSchematronRunTest:
|
|
Packit |
423ecb |
* @ctxt: the schema validation context
|
|
Packit |
423ecb |
* @test: the current test
|
|
Packit |
423ecb |
* @instance: the document instace tree
|
|
Packit |
423ecb |
* @cur: the current node in the instance
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Validate a rule against a tree instance at a given position
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Returns 1 in case of success, 0 if error and -1 in case of internal error
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
static int
|
|
Packit |
423ecb |
xmlSchematronRunTest(xmlSchematronValidCtxtPtr ctxt,
|
|
Packit |
423ecb |
xmlSchematronTestPtr test, xmlDocPtr instance, xmlNodePtr cur, xmlSchematronPatternPtr pattern)
|
|
Packit |
423ecb |
{
|
|
Packit |
423ecb |
xmlXPathObjectPtr ret;
|
|
Packit |
423ecb |
int failed;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
failed = 0;
|
|
Packit |
423ecb |
ctxt->xctxt->doc = instance;
|
|
Packit |
423ecb |
ctxt->xctxt->node = cur;
|
|
Packit |
423ecb |
ret = xmlXPathCompiledEval(test->comp, ctxt->xctxt);
|
|
Packit |
423ecb |
if (ret == NULL) {
|
|
Packit |
423ecb |
failed = 1;
|
|
Packit |
423ecb |
} else {
|
|
Packit |
423ecb |
switch (ret->type) {
|
|
Packit |
423ecb |
case XPATH_XSLT_TREE:
|
|
Packit |
423ecb |
case XPATH_NODESET:
|
|
Packit |
423ecb |
if ((ret->nodesetval == NULL) ||
|
|
Packit |
423ecb |
(ret->nodesetval->nodeNr == 0))
|
|
Packit |
423ecb |
failed = 1;
|
|
Packit |
423ecb |
break;
|
|
Packit |
423ecb |
case XPATH_BOOLEAN:
|
|
Packit |
423ecb |
failed = !ret->boolval;
|
|
Packit |
423ecb |
break;
|
|
Packit |
423ecb |
case XPATH_NUMBER:
|
|
Packit |
423ecb |
if ((xmlXPathIsNaN(ret->floatval)) ||
|
|
Packit |
423ecb |
(ret->floatval == 0.0))
|
|
Packit |
423ecb |
failed = 1;
|
|
Packit |
423ecb |
break;
|
|
Packit |
423ecb |
case XPATH_STRING:
|
|
Packit |
423ecb |
if ((ret->stringval == NULL) ||
|
|
Packit |
423ecb |
(ret->stringval[0] == 0))
|
|
Packit |
423ecb |
failed = 1;
|
|
Packit |
423ecb |
break;
|
|
Packit |
423ecb |
case XPATH_UNDEFINED:
|
|
Packit |
423ecb |
case XPATH_POINT:
|
|
Packit |
423ecb |
case XPATH_RANGE:
|
|
Packit |
423ecb |
case XPATH_LOCATIONSET:
|
|
Packit |
423ecb |
case XPATH_USERS:
|
|
Packit |
423ecb |
failed = 1;
|
|
Packit |
423ecb |
break;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
xmlXPathFreeObject(ret);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
if ((failed) && (test->type == XML_SCHEMATRON_ASSERT))
|
|
Packit |
423ecb |
ctxt->nberrors++;
|
|
Packit |
423ecb |
else if ((!failed) && (test->type == XML_SCHEMATRON_REPORT))
|
|
Packit |
423ecb |
ctxt->nberrors++;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
xmlSchematronReportSuccess(ctxt, test, cur, pattern, !failed);
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
return(!failed);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/**
|
|
Packit |
423ecb |
* xmlSchematronValidateDoc:
|
|
Packit |
423ecb |
* @ctxt: the schema validation context
|
|
Packit |
423ecb |
* @instance: the document instace tree
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Validate a tree instance against the schematron
|
|
Packit |
423ecb |
*
|
|
Packit |
423ecb |
* Returns 0 in case of success, -1 in case of internal error
|
|
Packit |
423ecb |
* and an error count otherwise.
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
int
|
|
Packit |
423ecb |
xmlSchematronValidateDoc(xmlSchematronValidCtxtPtr ctxt, xmlDocPtr instance)
|
|
Packit |
423ecb |
{
|
|
Packit |
423ecb |
xmlNodePtr cur, root;
|
|
Packit |
423ecb |
xmlSchematronPatternPtr pattern;
|
|
Packit |
423ecb |
xmlSchematronRulePtr rule;
|
|
Packit |
423ecb |
xmlSchematronTestPtr test;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
if ((ctxt == NULL) || (ctxt->schema == NULL) ||
|
|
Packit |
423ecb |
(ctxt->schema->rules == NULL) || (instance == NULL))
|
|
Packit |
423ecb |
return(-1);
|
|
Packit |
423ecb |
ctxt->nberrors = 0;
|
|
Packit |
423ecb |
root = xmlDocGetRootElement(instance);
|
|
Packit |
423ecb |
if (root == NULL) {
|
|
Packit |
423ecb |
TODO
|
|
Packit |
423ecb |
ctxt->nberrors++;
|
|
Packit |
423ecb |
return(1);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
if ((ctxt->flags & XML_SCHEMATRON_OUT_QUIET) ||
|
|
Packit |
423ecb |
(ctxt->flags == 0)) {
|
|
Packit |
423ecb |
/*
|
|
Packit |
423ecb |
* we are just trying to assert the validity of the document,
|
|
Packit |
423ecb |
* speed primes over the output, run in a single pass
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
cur = root;
|
|
Packit |
423ecb |
while (cur != NULL) {
|
|
Packit |
423ecb |
rule = ctxt->schema->rules;
|
|
Packit |
423ecb |
while (rule != NULL) {
|
|
Packit |
423ecb |
if (xmlPatternMatch(rule->pattern, cur) == 1) {
|
|
Packit |
423ecb |
test = rule->tests;
|
|
Packit |
423ecb |
while (test != NULL) {
|
|
Packit |
423ecb |
xmlSchematronRunTest(ctxt, test, instance, cur, (xmlSchematronPatternPtr)rule->pattern);
|
|
Packit |
423ecb |
test = test->next;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
rule = rule->next;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
cur = xmlSchematronNextNode(cur);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
} else {
|
|
Packit |
423ecb |
/*
|
|
Packit |
423ecb |
* Process all contexts one at a time
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
pattern = ctxt->schema->patterns;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
while (pattern != NULL) {
|
|
Packit |
423ecb |
xmlSchematronReportPattern(ctxt, pattern);
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
/*
|
|
Packit |
423ecb |
* TODO convert the pattern rule to a direct XPath and
|
|
Packit |
423ecb |
* compute directly instead of using the pattern matching
|
|
Packit |
423ecb |
* over the full document...
|
|
Packit |
423ecb |
* Check the exact semantic
|
|
Packit |
423ecb |
*/
|
|
Packit |
423ecb |
cur = root;
|
|
Packit |
423ecb |
while (cur != NULL) {
|
|
Packit |
423ecb |
rule = pattern->rules;
|
|
Packit |
423ecb |
while (rule != NULL) {
|
|
Packit |
423ecb |
if (xmlPatternMatch(rule->pattern, cur) == 1) {
|
|
Packit |
423ecb |
test = rule->tests;
|
|
Packit |
423ecb |
while (test != NULL) {
|
|
Packit |
423ecb |
xmlSchematronRunTest(ctxt, test, instance, cur, pattern);
|
|
Packit |
423ecb |
test = test->next;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
rule = rule->patnext;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
cur = xmlSchematronNextNode(cur);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
pattern = pattern->next;
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
return(ctxt->nberrors);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
#ifdef STANDALONE
|
|
Packit |
423ecb |
int
|
|
Packit |
423ecb |
main(void)
|
|
Packit |
423ecb |
{
|
|
Packit |
423ecb |
int ret;
|
|
Packit |
423ecb |
xmlDocPtr instance;
|
|
Packit |
423ecb |
xmlSchematronParserCtxtPtr pctxt;
|
|
Packit |
423ecb |
xmlSchematronValidCtxtPtr vctxt;
|
|
Packit |
423ecb |
xmlSchematronPtr schema = NULL;
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
pctxt = xmlSchematronNewParserCtxt("tst.sct");
|
|
Packit |
423ecb |
if (pctxt == NULL) {
|
|
Packit |
423ecb |
fprintf(stderr, "failed to build schematron parser\n");
|
|
Packit |
423ecb |
} else {
|
|
Packit |
423ecb |
schema = xmlSchematronParse(pctxt);
|
|
Packit |
423ecb |
if (schema == NULL) {
|
|
Packit |
423ecb |
fprintf(stderr, "failed to compile schematron\n");
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
xmlSchematronFreeParserCtxt(pctxt);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
instance = xmlReadFile("tst.sct", NULL,
|
|
Packit |
423ecb |
XML_PARSE_NOENT | XML_PARSE_NOCDATA);
|
|
Packit |
423ecb |
if (instance == NULL) {
|
|
Packit |
423ecb |
fprintf(stderr, "failed to parse instance\n");
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
if ((schema != NULL) && (instance != NULL)) {
|
|
Packit |
423ecb |
vctxt = xmlSchematronNewValidCtxt(schema);
|
|
Packit |
423ecb |
if (vctxt == NULL) {
|
|
Packit |
423ecb |
fprintf(stderr, "failed to build schematron validator\n");
|
|
Packit |
423ecb |
} else {
|
|
Packit |
423ecb |
ret = xmlSchematronValidateDoc(vctxt, instance);
|
|
Packit |
423ecb |
xmlSchematronFreeValidCtxt(vctxt);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
xmlSchematronFree(schema);
|
|
Packit |
423ecb |
xmlFreeDoc(instance);
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
xmlCleanupParser();
|
|
Packit |
423ecb |
xmlMemoryDump();
|
|
Packit |
423ecb |
|
|
Packit |
423ecb |
return (0);
|
|
Packit |
423ecb |
}
|
|
Packit |
423ecb |
#endif
|
|
Packit |
423ecb |
#define bottom_schematron
|
|
Packit |
423ecb |
#include "elfgcchack.h"
|
|
Packit |
423ecb |
#endif /* LIBXML_SCHEMATRON_ENABLED */
|