123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785 |
- /*
- * 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;
- /* error reporting 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 */
- };
- 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 reporting 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
- * @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 xmlSchematronTestPtr
- xmlSchematronAddTest(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 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);
- 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 xmlSchematronRulePtr
- xmlSchematronAddRule(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;
- prev->patnext = 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);
- if (rules->report != NULL)
- xmlFree(rules->report);
- xmlFree(rules);
- rules = next;
- }
- }
- /**
- * xmlSchematronAddPattern:
- * @ctxt: the schema parsing context
- * @schema: a schema structure
- * @node: the node hosting the pattern
- * @id: the id or name of the pattern
- *
- * Add a pattern to a schematron
- *
- * Returns the new pointer or NULL in case of error
- */
- static xmlSchematronPatternPtr
- xmlSchematronAddPattern(xmlSchematronParserCtxtPtr ctxt,
- xmlSchematronPtr schema, xmlNodePtr node, xmlChar *name)
- {
- xmlSchematronPatternPtr ret;
- if ((ctxt == NULL) || (schema == NULL) || (node == NULL) || (name == NULL))
- return(NULL);
- ret = (xmlSchematronPatternPtr) xmlMalloc(sizeof(xmlSchematronPattern));
- if (ret == NULL) {
- xmlSchematronPErrMemory(ctxt, "allocating schema pattern", node);
- return (NULL);
- }
- memset(ret, 0, sizeof(xmlSchematronPattern));
- ret->name = name;
- ret->next = NULL;
- if (schema->patterns == NULL) {
- schema->patterns = ret;
- } else {
- xmlSchematronPatternPtr prev = schema->patterns;
- while (prev->next != NULL)
- prev = prev->next;
- prev->next = ret;
- }
- return (ret);
- }
- /**
- * xmlSchematronFreePatterns:
- * @patterns: a list of patterns
- *
- * Free a list of patterns.
- */
- static void
- xmlSchematronFreePatterns(xmlSchematronPatternPtr patterns) {
- xmlSchematronPatternPtr next;
- while (patterns != NULL) {
- next = patterns->next;
- if (patterns->name != NULL)
- xmlFree(patterns->name);
- xmlFree(patterns);
- patterns = 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((char **) schema->namespaces);
-
- xmlSchematronFreeRules(schema->rules);
- xmlSchematronFreePatterns(schema->patterns);
- 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 = NULL;
- 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((char **) ctxt->namespaces);
- xmlDictFree(ctxt->dict);
- xmlFree(ctxt);
- }
- #if 0
- /**
- * 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);
- }
- #endif
- /**
- * 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((xmlChar **) 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,
- xmlSchematronPatternPtr pattern,
- xmlNodePtr rule)
- {
- xmlNodePtr cur;
- int nbChecks = 0;
- xmlChar *test;
- xmlChar *context;
- xmlChar *report;
- 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, pattern,
- rule, context, NULL);
- 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 {
- /* TODO will need dynamic processing instead */
- report = xmlNodeGetContent(cur);
- testptr = xmlSchematronAddTest(ctxt, XML_SCHEMATRON_ASSERT,
- ruleptr, cur, test, report);
- 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 {
- /* TODO will need dynamic processing instead */
- report = xmlNodeGetContent(cur);
- testptr = xmlSchematronAddTest(ctxt, XML_SCHEMATRON_REPORT,
- ruleptr, cur, test, report);
- 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;
- xmlSchematronPatternPtr pattern;
- int nbRules = 0;
- xmlChar *id;
- if ((ctxt == NULL) || (pat == NULL)) return;
- id = xmlGetNoNsProp(pat, BAD_CAST "id");
- if (id == NULL) {
- id = xmlGetNoNsProp(pat, BAD_CAST "name");
- }
- pattern = xmlSchematronAddPattern(ctxt, ctxt->schema, pat, id);
- if (pattern == NULL) {
- if (id != NULL)
- xmlFree(id);
- return;
- }
- cur = pat->children;
- NEXT_SCHEMATRON(cur);
- while (cur != NULL) {
- if (IS_SCHEMATRON(cur, "rule")) {
- xmlSchematronParseRule(ctxt, pattern, 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);
- }
- }
- #if 0
- /**
- * 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);
- }
- xmlFree(href);
- if (base != NULL)
- xmlFree(base);
- if (URI != NULL)
- xmlFree(URI);
- return(ret);
- }
- #endif
- /**
- * 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);
- }
- ctxt->preserve = 0;
- } 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);
- ctxt->preserve = 0;
- } else if (ctxt->doc != NULL) {
- doc = ctxt->doc;
- preserve = 1;
- ctxt->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;
- }
- /* the original document must be kept for reporting */
- ret->doc = doc;
- if (preserve) {
- ret->preserve = 1;
- }
- preserve = 1;
- exit:
- if (!preserve) {
- xmlFreeDoc(doc);
- }
- if (ret != NULL) {
- 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 xmlNodePtr
- xmlSchematronGetNode(xmlSchematronValidCtxtPtr ctxt,
- xmlNodePtr cur, const xmlChar *xpath) {
- xmlNodePtr node = NULL;
- xmlXPathObjectPtr ret;
- if ((ctxt == NULL) || (cur == NULL) || (xpath == NULL))
- return(NULL);
- ctxt->xctxt->doc = cur->doc;
- ctxt->xctxt->node = cur;
- ret = xmlXPathEval(xpath, ctxt->xctxt);
- if (ret == NULL)
- return(NULL);
- if ((ret->type == XPATH_NODESET) &&
- (ret->nodesetval != NULL) && (ret->nodesetval->nodeNr > 0))
- node = ret->nodesetval->nodeTab[0];
- xmlXPathFreeObject(ret);
- return(node);
- }
- /**
- * xmlSchematronReportOutput:
- * @ctxt: the validation context
- * @cur: the current node tested
- * @msg: the message output
- *
- * Output part of the report to whatever channel the user selected
- */
- static void
- xmlSchematronReportOutput(xmlSchematronValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
- xmlNodePtr cur ATTRIBUTE_UNUSED,
- const char *msg) {
- /* TODO */
- fprintf(stderr, "%s", msg);
- }
- /**
- * xmlSchematronFormatReport:
- * @ctxt: the validation context
- * @test: the test node
- * @cur: the current node tested
- *
- * Build the string being reported to the user.
- *
- * Returns a report string or NULL in case of error. The string needs
- * to be deallocated by teh caller
- */
- static xmlChar *
- xmlSchematronFormatReport(xmlSchematronValidCtxtPtr ctxt,
- xmlNodePtr test, xmlNodePtr cur) {
- xmlChar *ret = NULL;
- xmlNodePtr child, node;
- if ((test == NULL) || (cur == NULL))
- return(ret);
- child = test->children;
- while (child != NULL) {
- if ((child->type == XML_TEXT_NODE) ||
- (child->type == XML_CDATA_SECTION_NODE))
- ret = xmlStrcat(ret, child->content);
- else if (IS_SCHEMATRON(child, "name")) {
- xmlChar *path;
- path = xmlGetNoNsProp(child, BAD_CAST "path");
- node = cur;
- if (path != NULL) {
- node = xmlSchematronGetNode(ctxt, cur, path);
- if (node == NULL)
- node = cur;
- xmlFree(path);
- }
- if ((node->ns == NULL) || (node->ns->prefix == NULL))
- ret = xmlStrcat(ret, node->name);
- else {
- ret = xmlStrcat(ret, node->ns->prefix);
- ret = xmlStrcat(ret, BAD_CAST ":");
- ret = xmlStrcat(ret, node->name);
- }
- } else {
- child = child->next;
- continue;
- }
- /*
- * remove superfluous \n
- */
- if (ret != NULL) {
- int len = xmlStrlen(ret);
- xmlChar c;
- if (len > 0) {
- c = ret[len - 1];
- if ((c == ' ') || (c == '\n') || (c == '\r') || (c == '\t')) {
- while ((c == ' ') || (c == '\n') ||
- (c == '\r') || (c == '\t')) {
- len--;
- if (len == 0)
- break;
- c = ret[len - 1];
- }
- ret[len] = ' ';
- ret[len + 1] = 0;
- }
- }
- }
- child = child->next;
- }
- return(ret);
- }
- /**
- * xmlSchematronReportSuccess:
- * @ctxt: the validation context
- * @test: the compiled test
- * @cur: the current node tested
- * @success: boolean value for the result
- *
- * called from the validation engine when an assert or report test have
- * been done.
- */
- static void
- xmlSchematronReportSuccess(xmlSchematronValidCtxtPtr ctxt,
- xmlSchematronTestPtr test, xmlNodePtr cur, xmlSchematronPatternPtr pattern, int success) {
- if ((ctxt == NULL) || (cur == NULL) || (test == NULL))
- return;
- /* if quiet and not SVRL report only failures */
- if ((ctxt->flags & XML_SCHEMATRON_OUT_QUIET) &&
- ((ctxt->flags & XML_SCHEMATRON_OUT_XML) == 0) &&
- (test->type == XML_SCHEMATRON_REPORT))
- return;
- if (ctxt->flags & XML_SCHEMATRON_OUT_XML) {
- TODO
- } else {
- xmlChar *path;
- char msg[1000];
- long line;
- const xmlChar *report = NULL;
- if (((test->type == XML_SCHEMATRON_REPORT) & (!success)) ||
- ((test->type == XML_SCHEMATRON_ASSERT) & (success)))
- return;
- line = xmlGetLineNo(cur);
- path = xmlGetNodePath(cur);
- if (path == NULL)
- path = (xmlChar *) cur->name;
- #if 0
- if ((test->report != NULL) && (test->report[0] != 0))
- report = test->report;
- #endif
- if (test->node != NULL)
- report = xmlSchematronFormatReport(ctxt, test->node, cur);
- if (report == NULL) {
- if (test->type == XML_SCHEMATRON_ASSERT) {
- report = xmlStrdup((const xmlChar *) "node failed assert");
- } else {
- report = xmlStrdup((const xmlChar *) "node failed report");
- }
- }
- snprintf(msg, 999, "%s line %ld: %s\n", (const char *) path,
- line, (const char *) report);
- if (ctxt->flags & XML_SCHEMATRON_OUT_ERROR) {
- xmlStructuredErrorFunc schannel = NULL;
- xmlGenericErrorFunc channel = NULL;
- void *data = NULL;
- if (ctxt != NULL) {
- if (ctxt->serror != NULL)
- schannel = ctxt->serror;
- else
- channel = ctxt->error;
- data = ctxt->userData;
- }
- __xmlRaiseError(schannel, channel, data,
- NULL, cur, XML_FROM_SCHEMATRONV,
- (test->type == XML_SCHEMATRON_ASSERT)?XML_SCHEMATRONV_ASSERT:XML_SCHEMATRONV_REPORT,
- XML_ERR_ERROR, NULL, line,
- (pattern == NULL)?NULL:((const char *) pattern->name),
- (const char *) path,
- (const char *) report, 0, 0,
- "%s", msg);
- } else {
- xmlSchematronReportOutput(ctxt, cur, &msg[0]);
- }
- xmlFree((char *) report);
- if ((path != NULL) && (path != (xmlChar *) cur->name))
- xmlFree(path);
- }
- }
- /**
- * xmlSchematronReportPattern:
- * @ctxt: the validation context
- * @pattern: the current pattern
- *
- * called from the validation engine when starting to check a pattern
- */
- static void
- xmlSchematronReportPattern(xmlSchematronValidCtxtPtr ctxt,
- xmlSchematronPatternPtr pattern) {
- if ((ctxt == NULL) || (pattern == NULL))
- return;
- if ((ctxt->flags & XML_SCHEMATRON_OUT_QUIET) || (ctxt->flags & XML_SCHEMATRON_OUT_ERROR)) /* Error gives pattern name as part of error */
- return;
- if (ctxt->flags & XML_SCHEMATRON_OUT_XML) {
- TODO
- } else {
- char msg[1000];
- if (pattern->name == NULL)
- return;
- snprintf(msg, 999, "Pattern: %s\n", (const char *) pattern->name);
- xmlSchematronReportOutput(ctxt, NULL, &msg[0]);
- }
- }
- /************************************************************************
- * *
- * Validation against a Schematrontron *
- * *
- ************************************************************************/
- /**
- * xmlSchematronSetValidStructuredErrors:
- * @ctxt: a Schematron validation context
- * @serror: the structured error function
- * @ctx: the functions context
- *
- * Set the structured error callback
- */
- void
- xmlSchematronSetValidStructuredErrors(xmlSchematronValidCtxtPtr ctxt,
- xmlStructuredErrorFunc serror, void *ctx)
- {
- if (ctxt == NULL)
- return;
- ctxt->serror = serror;
- ctxt->error = NULL;
- ctxt->warning = NULL;
- ctxt->userData = ctx;
- }
- /**
- * 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);
- ret->flags = options;
- 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) break;
- 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, xmlSchematronPatternPtr pattern)
- {
- 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;
- }
- xmlXPathFreeObject(ret);
- }
- if ((failed) && (test->type == XML_SCHEMATRON_ASSERT))
- ctxt->nberrors++;
- else if ((!failed) && (test->type == XML_SCHEMATRON_REPORT))
- ctxt->nberrors++;
- xmlSchematronReportSuccess(ctxt, test, cur, pattern, !failed);
- 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, root;
- xmlSchematronPatternPtr pattern;
- xmlSchematronRulePtr rule;
- xmlSchematronTestPtr test;
- if ((ctxt == NULL) || (ctxt->schema == NULL) ||
- (ctxt->schema->rules == NULL) || (instance == NULL))
- return(-1);
- ctxt->nberrors = 0;
- root = xmlDocGetRootElement(instance);
- if (root == NULL) {
- TODO
- ctxt->nberrors++;
- return(1);
- }
- if ((ctxt->flags & XML_SCHEMATRON_OUT_QUIET) ||
- (ctxt->flags == 0)) {
- /*
- * we are just trying to assert the validity of the document,
- * speed primes over the output, run in a single pass
- */
- cur = root;
- while (cur != NULL) {
- rule = ctxt->schema->rules;
- while (rule != NULL) {
- if (xmlPatternMatch(rule->pattern, cur) == 1) {
- test = rule->tests;
- while (test != NULL) {
- xmlSchematronRunTest(ctxt, test, instance, cur, (xmlSchematronPatternPtr)rule->pattern);
- test = test->next;
- }
- }
- rule = rule->next;
- }
-
- cur = xmlSchematronNextNode(cur);
- }
- } else {
- /*
- * Process all contexts one at a time
- */
- pattern = ctxt->schema->patterns;
-
- while (pattern != NULL) {
- xmlSchematronReportPattern(ctxt, pattern);
- /*
- * TODO convert the pattern rule to a direct XPath and
- * compute directly instead of using the pattern matching
- * over the full document...
- * Check the exact semantic
- */
- cur = root;
- while (cur != NULL) {
- rule = pattern->rules;
- while (rule != NULL) {
- if (xmlPatternMatch(rule->pattern, cur) == 1) {
- test = rule->tests;
- while (test != NULL) {
- xmlSchematronRunTest(ctxt, test, instance, cur, pattern);
- test = test->next;
- }
- }
- rule = rule->patnext;
- }
-
- cur = xmlSchematronNextNode(cur);
- }
- pattern = pattern->next;
- }
- }
- 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
- #define bottom_schematron
- #include "elfgcchack.h"
- #endif /* LIBXML_SCHEMATRON_ENABLED */
|