📄 schematron.c
字号:
/* * schematron.c : implementation of the Schematron schema validity checking * * See Copyright for the status of this software. * * Daniel Veillard <daniel@veillard.com> *//* * TODO: * + double check the semantic, especially * - multiple rules applying in a single pattern/node * - the semantic of libxml2 patterns vs. XSLT production referenced * by the spec. * + export of results in SVRL * + full parsing and coverage of the spec, conformance of the input to the * spec * + divergences between the draft and the ISO proposed standard :-( * + hook and test include * + try and compare with the XSLT version */#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#define SCT_OLD_NS BAD_CAST "http://www.ascc.net/xml/schematron"#define XML_SCHEMATRON_NS BAD_CAST "http://purl.oclc.org/dsdl/schematron"static const xmlChar *xmlSchematronNs = XML_SCHEMATRON_NS;static const xmlChar *xmlOldSchematronNs = SCT_OLD_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)) || \ (xmlStrEqual(node->ns->href, xmlOldSchematronNs))))#define NEXT_SCHEMATRON(node) \ while (node != NULL) { \ if ((node->type == XML_ELEMENT_NODE ) && (node->ns != NULL) && \ ((xmlStrEqual(node->ns->href, xmlSchematronNs)) || \ (xmlStrEqual(node->ns->href, xmlOldSchematronNs)))) \ break; \ node = node->next; \ }/** * TODO: * * macro to flag unimplemented blocks */#define TODO \ xmlGenericError(xmlGenericErrorContext, \ "Unimplemented block at %s:%d\n", \ __FILE__, __LINE__);typedef enum { XML_SCHEMATRON_ASSERT=1, XML_SCHEMATRON_REPORT=2} xmlSchematronTestType;/** * _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 */ xmlSchematronTestType type; /* the test type */ xmlNodePtr node; /* the node in the tree */ xmlChar *test; /* the expression to test */ xmlXPathCompExprPtr comp; /* the compiled expression */ xmlChar *report; /* the message to report */};/** * _xmlSchematronRule: * * A Schematrons rule */typedef struct _xmlSchematronRule xmlSchematronRule;typedef xmlSchematronRule *xmlSchematronRulePtr;struct _xmlSchematronRule { xmlSchematronRulePtr next; /* the next rule in the list */ xmlSchematronRulePtr patnext;/* the next rule in the pattern 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 */ xmlChar *report; /* the message to report */};/** * _xmlSchematronPattern: * * A Schematrons pattern */typedef struct _xmlSchematronPattern xmlSchematronPattern;typedef xmlSchematronPattern *xmlSchematronPatternPtr;struct _xmlSchematronPattern { xmlSchematronPatternPtr next;/* the next pattern in the list */ xmlSchematronRulePtr rules; /* the list of rules */ xmlChar *name; /* the name of the pattern */};/** * _xmlSchematron: * * A Schematrons definition */struct _xmlSchematron { const xmlChar *name; /* schema name */ int preserve; /* was the document passed 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 */ xmlSchematronPatternPtr patterns;/* the patterns found */ 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 voidxmlSchematronPErrMemory(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 voidxmlSchematronPErr(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 voidxmlSchematronVErrMemory(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 * @type: the type of test * @rule: the parent rule * @node: the node hosting the test * @test: the associated test * @report: the associated report string * * Add a test to a schematron * * Returns the new pointer or NULL in case of error */static xmlSchematronTestPtrxmlSchematronAddTest(xmlSchematronParserCtxtPtr ctxt, xmlSchematronTestType type, xmlSchematronRulePtr rule, xmlNodePtr node, xmlChar *test, xmlChar *report){ 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->report = report; ret->next = NULL; if (rule->tests == NULL) { rule->tests = ret; } else { xmlSchematronTestPtr prev = rule->tests; while (prev->next != NULL) prev = prev->next; prev->next = ret; } return (ret);}/** * xmlSchematronFreeTests: * @tests: a list of tests * * Free a list of tests. */static voidxmlSchematronFreeTests(xmlSchematronTestPtr tests) { xmlSchematronTestPtr next; while (tests != NULL) { next = tests->next; if (tests->test != NULL) xmlFree(tests->test); if (tests->comp != NULL) xmlXPathFreeCompExpr(tests->comp); if (tests->report != NULL) xmlFree(tests->report); 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 * @report: the associated report string * * Add a rule to a schematron * * Returns the new pointer or NULL in case of error */static xmlSchematronRulePtrxmlSchematronAddRule(xmlSchematronParserCtxtPtr ctxt, xmlSchematronPtr schema, xmlSchematronPatternPtr pat, xmlNodePtr node, xmlChar *context, xmlChar *report){ 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->pattern = pattern; ret->report = report; ret->next = NULL; if (schema->rules == NULL) { schema->rules = ret; } else { xmlSchematronRulePtr prev = schema->rules; while (prev->next != NULL) prev = prev->next; prev->next = ret; } ret->patnext = NULL; if (pat->rules == NULL) { pat->rules = ret; } else { xmlSchematronRulePtr prev = pat->rules; while (prev->patnext != NULL) prev = prev->patnext;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -