12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787 |
- /*
- * 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 dictionary 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 */
- #ifdef LIBXML_OUTPUT_ENABLED
- xmlOutputWriteCallback iowrite; /* if using XML_SCHEMATRON_OUT_IO */
- xmlOutputCloseCallback ioclose;
- #endif
- 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; /* dictionary 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 information
- *
- * 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 LIBXML_ATTR_FORMAT(4,0)
- 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 information
- *
- * 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 Schema structure 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 the 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 instance 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 instance 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 */
|