Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenschematron.c
Go to the documentation of this file.
00001 /* 00002 * schematron.c : implementation of the Schematron schema validity checking 00003 * 00004 * See Copyright for the status of this software. 00005 * 00006 * Daniel Veillard <daniel@veillard.com> 00007 */ 00008 00009 /* 00010 * TODO: 00011 * + double check the semantic, especially 00012 * - multiple rules applying in a single pattern/node 00013 * - the semantic of libxml2 patterns vs. XSLT production referenced 00014 * by the spec. 00015 * + export of results in SVRL 00016 * + full parsing and coverage of the spec, conformance of the input to the 00017 * spec 00018 * + divergences between the draft and the ISO proposed standard :-( 00019 * + hook and test include 00020 * + try and compare with the XSLT version 00021 */ 00022 00023 #define IN_LIBXML 00024 #include "libxml.h" 00025 00026 #ifdef LIBXML_SCHEMATRON_ENABLED 00027 00028 #include <string.h> 00029 #include <libxml/parser.h> 00030 #include <libxml/tree.h> 00031 #include <libxml/uri.h> 00032 #include <libxml/xpath.h> 00033 #include <libxml/xpathInternals.h> 00034 #include <libxml/pattern.h> 00035 #include <libxml/schematron.h> 00036 00037 #define SCHEMATRON_PARSE_OPTIONS XML_PARSE_NOENT 00038 00039 #define SCT_OLD_NS BAD_CAST "http://www.ascc.net/xml/schematron" 00040 00041 #define XML_SCHEMATRON_NS BAD_CAST "http://purl.oclc.org/dsdl/schematron" 00042 00043 00044 static const xmlChar *xmlSchematronNs = XML_SCHEMATRON_NS; 00045 static const xmlChar *xmlOldSchematronNs = SCT_OLD_NS; 00046 00047 #define IS_SCHEMATRON(node, elem) \ 00048 ((node != NULL) && (node->type == XML_ELEMENT_NODE ) && \ 00049 (node->ns != NULL) && \ 00050 (xmlStrEqual(node->name, (const xmlChar *) elem)) && \ 00051 ((xmlStrEqual(node->ns->href, xmlSchematronNs)) || \ 00052 (xmlStrEqual(node->ns->href, xmlOldSchematronNs)))) 00053 00054 #define NEXT_SCHEMATRON(node) \ 00055 while (node != NULL) { \ 00056 if ((node->type == XML_ELEMENT_NODE ) && (node->ns != NULL) && \ 00057 ((xmlStrEqual(node->ns->href, xmlSchematronNs)) || \ 00058 (xmlStrEqual(node->ns->href, xmlOldSchematronNs)))) \ 00059 break; \ 00060 node = node->next; \ 00061 } 00062 00068 #define TODO \ 00069 xmlGenericError(xmlGenericErrorContext, \ 00070 "Unimplemented block at %s:%d\n", \ 00071 __FILE__, __LINE__); 00072 00073 typedef enum { 00074 XML_SCHEMATRON_ASSERT=1, 00075 XML_SCHEMATRON_REPORT=2 00076 } xmlSchematronTestType; 00077 00083 typedef struct _xmlSchematronTest xmlSchematronTest; 00084 typedef xmlSchematronTest *xmlSchematronTestPtr; 00085 struct _xmlSchematronTest { 00086 xmlSchematronTestPtr next; /* the next test in the list */ 00087 xmlSchematronTestType type; /* the test type */ 00088 xmlNodePtr node; /* the node in the tree */ 00089 xmlChar *test; /* the expression to test */ 00090 xmlXPathCompExprPtr comp; /* the compiled expression */ 00091 xmlChar *report; /* the message to report */ 00092 }; 00093 00099 typedef struct _xmlSchematronRule xmlSchematronRule; 00100 typedef xmlSchematronRule *xmlSchematronRulePtr; 00101 struct _xmlSchematronRule { 00102 xmlSchematronRulePtr next; /* the next rule in the list */ 00103 xmlSchematronRulePtr patnext;/* the next rule in the pattern list */ 00104 xmlNodePtr node; /* the node in the tree */ 00105 xmlChar *context; /* the context evaluation rule */ 00106 xmlSchematronTestPtr tests; /* the list of tests */ 00107 xmlPatternPtr pattern; /* the compiled pattern associated */ 00108 xmlChar *report; /* the message to report */ 00109 }; 00110 00116 typedef struct _xmlSchematronPattern xmlSchematronPattern; 00117 typedef xmlSchematronPattern *xmlSchematronPatternPtr; 00118 struct _xmlSchematronPattern { 00119 xmlSchematronPatternPtr next;/* the next pattern in the list */ 00120 xmlSchematronRulePtr rules; /* the list of rules */ 00121 xmlChar *name; /* the name of the pattern */ 00122 }; 00123 00129 struct _xmlSchematron { 00130 const xmlChar *name; /* schema name */ 00131 int preserve; /* was the document passed by the user */ 00132 xmlDocPtr doc; /* pointer to the parsed document */ 00133 int flags; /* specific to this schematron */ 00134 00135 void *_private; /* unused by the library */ 00136 xmlDictPtr dict; /* the dictionnary used internally */ 00137 00138 const xmlChar *title; /* the title if any */ 00139 00140 int nbNs; /* the number of namespaces */ 00141 00142 int nbPattern; /* the number of patterns */ 00143 xmlSchematronPatternPtr patterns;/* the patterns found */ 00144 xmlSchematronRulePtr rules; /* the rules gathered */ 00145 int nbNamespaces; /* number of namespaces in the array */ 00146 int maxNamespaces; /* size of the array */ 00147 const xmlChar **namespaces; /* the array of namespaces */ 00148 }; 00149 00155 struct _xmlSchematronValidCtxt { 00156 int type; 00157 int flags; /* an or of xmlSchematronValidOptions */ 00158 00159 xmlDictPtr dict; 00160 int nberrors; 00161 int err; 00162 00163 xmlSchematronPtr schema; 00164 xmlXPathContextPtr xctxt; 00165 00166 FILE *outputFile; /* if using XML_SCHEMATRON_OUT_FILE */ 00167 xmlBufferPtr outputBuffer; /* if using XML_SCHEMATRON_OUT_BUFFER */ 00168 xmlOutputWriteCallback iowrite; /* if using XML_SCHEMATRON_OUT_IO */ 00169 xmlOutputCloseCallback ioclose; 00170 void *ioctx; 00171 00172 /* error reporting data */ 00173 void *userData; /* user specific data block */ 00174 xmlSchematronValidityErrorFunc error;/* the callback in case of errors */ 00175 xmlSchematronValidityWarningFunc warning;/* callback in case of warning */ 00176 xmlStructuredErrorFunc serror; /* the structured function */ 00177 }; 00178 00179 struct _xmlSchematronParserCtxt { 00180 int type; 00181 const xmlChar *URL; 00182 xmlDocPtr doc; 00183 int preserve; /* Whether the doc should be freed */ 00184 const char *buffer; 00185 int size; 00186 00187 xmlDictPtr dict; /* dictionnary for interned string names */ 00188 00189 int nberrors; 00190 int err; 00191 xmlXPathContextPtr xctxt; /* the XPath context used for compilation */ 00192 xmlSchematronPtr schema; 00193 00194 int nbNamespaces; /* number of namespaces in the array */ 00195 int maxNamespaces; /* size of the array */ 00196 const xmlChar **namespaces; /* the array of namespaces */ 00197 00198 int nbIncludes; /* number of includes in the array */ 00199 int maxIncludes; /* size of the array */ 00200 xmlNodePtr *includes; /* the array of includes */ 00201 00202 /* error reporting data */ 00203 void *userData; /* user specific data block */ 00204 xmlSchematronValidityErrorFunc error;/* the callback in case of errors */ 00205 xmlSchematronValidityWarningFunc warning;/* callback in case of warning */ 00206 xmlStructuredErrorFunc serror; /* the structured function */ 00207 }; 00208 00209 #define XML_STRON_CTXT_PARSER 1 00210 #define XML_STRON_CTXT_VALIDATOR 2 00211 00212 /************************************************************************ 00213 * * 00214 * Error reporting * 00215 * * 00216 ************************************************************************/ 00217 00225 static void 00226 xmlSchematronPErrMemory(xmlSchematronParserCtxtPtr ctxt, 00227 const char *extra, xmlNodePtr node) 00228 { 00229 if (ctxt != NULL) 00230 ctxt->nberrors++; 00231 __xmlSimpleError(XML_FROM_SCHEMASP, XML_ERR_NO_MEMORY, node, NULL, 00232 extra); 00233 } 00234 00246 static void 00247 xmlSchematronPErr(xmlSchematronParserCtxtPtr ctxt, xmlNodePtr node, int error, 00248 const char *msg, const xmlChar * str1, const xmlChar * str2) 00249 { 00250 xmlGenericErrorFunc channel = NULL; 00251 xmlStructuredErrorFunc schannel = NULL; 00252 void *data = NULL; 00253 00254 if (ctxt != NULL) { 00255 ctxt->nberrors++; 00256 channel = ctxt->error; 00257 data = ctxt->userData; 00258 schannel = ctxt->serror; 00259 } 00260 __xmlRaiseError(schannel, channel, data, ctxt, node, XML_FROM_SCHEMASP, 00261 error, XML_ERR_ERROR, NULL, 0, 00262 (const char *) str1, (const char *) str2, NULL, 0, 0, 00263 msg, str1, str2); 00264 } 00265 00273 static void 00274 xmlSchematronVErrMemory(xmlSchematronValidCtxtPtr ctxt, 00275 const char *extra, xmlNodePtr node) 00276 { 00277 if (ctxt != NULL) { 00278 ctxt->nberrors++; 00279 ctxt->err = XML_SCHEMAV_INTERNAL; 00280 } 00281 __xmlSimpleError(XML_FROM_SCHEMASV, XML_ERR_NO_MEMORY, node, NULL, 00282 extra); 00283 } 00284 00285 /************************************************************************ 00286 * * 00287 * Parsing and compilation of the Schematrontrons * 00288 * * 00289 ************************************************************************/ 00290 00304 static xmlSchematronTestPtr 00305 xmlSchematronAddTest(xmlSchematronParserCtxtPtr ctxt, 00306 xmlSchematronTestType type, 00307 xmlSchematronRulePtr rule, 00308 xmlNodePtr node, xmlChar *test, xmlChar *report) 00309 { 00310 xmlSchematronTestPtr ret; 00311 xmlXPathCompExprPtr comp; 00312 00313 if ((ctxt == NULL) || (rule == NULL) || (node == NULL) || 00314 (test == NULL)) 00315 return(NULL); 00316 00317 /* 00318 * try first to compile the test expression 00319 */ 00320 comp = xmlXPathCtxtCompile(ctxt->xctxt, test); 00321 if (comp == NULL) { 00322 xmlSchematronPErr(ctxt, node, 00323 XML_SCHEMAP_NOROOT, 00324 "Failed to compile test expression %s", 00325 test, NULL); 00326 return(NULL); 00327 } 00328 00329 ret = (xmlSchematronTestPtr) xmlMalloc(sizeof(xmlSchematronTest)); 00330 if (ret == NULL) { 00331 xmlSchematronPErrMemory(ctxt, "allocating schema test", node); 00332 return (NULL); 00333 } 00334 memset(ret, 0, sizeof(xmlSchematronTest)); 00335 ret->type = type; 00336 ret->node = node; 00337 ret->test = test; 00338 ret->comp = comp; 00339 ret->report = report; 00340 ret->next = NULL; 00341 if (rule->tests == NULL) { 00342 rule->tests = ret; 00343 } else { 00344 xmlSchematronTestPtr prev = rule->tests; 00345 00346 while (prev->next != NULL) 00347 prev = prev->next; 00348 prev->next = ret; 00349 } 00350 return (ret); 00351 } 00352 00359 static void 00360 xmlSchematronFreeTests(xmlSchematronTestPtr tests) { 00361 xmlSchematronTestPtr next; 00362 00363 while (tests != NULL) { 00364 next = tests->next; 00365 if (tests->test != NULL) 00366 xmlFree(tests->test); 00367 if (tests->comp != NULL) 00368 xmlXPathFreeCompExpr(tests->comp); 00369 if (tests->report != NULL) 00370 xmlFree(tests->report); 00371 xmlFree(tests); 00372 tests = next; 00373 } 00374 } 00375 00388 static xmlSchematronRulePtr 00389 xmlSchematronAddRule(xmlSchematronParserCtxtPtr ctxt, xmlSchematronPtr schema, 00390 xmlSchematronPatternPtr pat, xmlNodePtr node, 00391 xmlChar *context, xmlChar *report) 00392 { 00393 xmlSchematronRulePtr ret; 00394 xmlPatternPtr pattern; 00395 00396 if ((ctxt == NULL) || (schema == NULL) || (node == NULL) || 00397 (context == NULL)) 00398 return(NULL); 00399 00400 /* 00401 * Try first to compile the pattern 00402 */ 00403 pattern = xmlPatterncompile(context, ctxt->dict, XML_PATTERN_XPATH, 00404 ctxt->namespaces); 00405 if (pattern == NULL) { 00406 xmlSchematronPErr(ctxt, node, 00407 XML_SCHEMAP_NOROOT, 00408 "Failed to compile context expression %s", 00409 context, NULL); 00410 } 00411 00412 ret = (xmlSchematronRulePtr) xmlMalloc(sizeof(xmlSchematronRule)); 00413 if (ret == NULL) { 00414 xmlSchematronPErrMemory(ctxt, "allocating schema rule", node); 00415 return (NULL); 00416 } 00417 memset(ret, 0, sizeof(xmlSchematronRule)); 00418 ret->node = node; 00419 ret->context = context; 00420 ret->pattern = pattern; 00421 ret->report = report; 00422 ret->next = NULL; 00423 if (schema->rules == NULL) { 00424 schema->rules = ret; 00425 } else { 00426 xmlSchematronRulePtr prev = schema->rules; 00427 00428 while (prev->next != NULL) 00429 prev = prev->next; 00430 prev->next = ret; 00431 } 00432 ret->patnext = NULL; 00433 if (pat->rules == NULL) { 00434 pat->rules = ret; 00435 } else { 00436 xmlSchematronRulePtr prev = pat->rules; 00437 00438 while (prev->patnext != NULL) 00439 prev = prev->patnext; 00440 prev->patnext = ret; 00441 } 00442 return (ret); 00443 } 00444 00451 static void 00452 xmlSchematronFreeRules(xmlSchematronRulePtr rules) { 00453 xmlSchematronRulePtr next; 00454 00455 while (rules != NULL) { 00456 next = rules->next; 00457 if (rules->tests) 00458 xmlSchematronFreeTests(rules->tests); 00459 if (rules->context != NULL) 00460 xmlFree(rules->context); 00461 if (rules->pattern) 00462 xmlFreePattern(rules->pattern); 00463 if (rules->report != NULL) 00464 xmlFree(rules->report); 00465 xmlFree(rules); 00466 rules = next; 00467 } 00468 } 00469 00481 static xmlSchematronPatternPtr 00482 xmlSchematronAddPattern(xmlSchematronParserCtxtPtr ctxt, 00483 xmlSchematronPtr schema, xmlNodePtr node, xmlChar *name) 00484 { 00485 xmlSchematronPatternPtr ret; 00486 00487 if ((ctxt == NULL) || (schema == NULL) || (node == NULL) || (name == NULL)) 00488 return(NULL); 00489 00490 ret = (xmlSchematronPatternPtr) xmlMalloc(sizeof(xmlSchematronPattern)); 00491 if (ret == NULL) { 00492 xmlSchematronPErrMemory(ctxt, "allocating schema pattern", node); 00493 return (NULL); 00494 } 00495 memset(ret, 0, sizeof(xmlSchematronPattern)); 00496 ret->name = name; 00497 ret->next = NULL; 00498 if (schema->patterns == NULL) { 00499 schema->patterns = ret; 00500 } else { 00501 xmlSchematronPatternPtr prev = schema->patterns; 00502 00503 while (prev->next != NULL) 00504 prev = prev->next; 00505 prev->next = ret; 00506 } 00507 return (ret); 00508 } 00509 00516 static void 00517 xmlSchematronFreePatterns(xmlSchematronPatternPtr patterns) { 00518 xmlSchematronPatternPtr next; 00519 00520 while (patterns != NULL) { 00521 next = patterns->next; 00522 if (patterns->name != NULL) 00523 xmlFree(patterns->name); 00524 xmlFree(patterns); 00525 patterns = next; 00526 } 00527 } 00528 00537 static xmlSchematronPtr 00538 xmlSchematronNewSchematron(xmlSchematronParserCtxtPtr ctxt) 00539 { 00540 xmlSchematronPtr ret; 00541 00542 ret = (xmlSchematronPtr) xmlMalloc(sizeof(xmlSchematron)); 00543 if (ret == NULL) { 00544 xmlSchematronPErrMemory(ctxt, "allocating schema", NULL); 00545 return (NULL); 00546 } 00547 memset(ret, 0, sizeof(xmlSchematron)); 00548 ret->dict = ctxt->dict; 00549 xmlDictReference(ret->dict); 00550 00551 return (ret); 00552 } 00553 00560 void 00561 xmlSchematronFree(xmlSchematronPtr schema) 00562 { 00563 if (schema == NULL) 00564 return; 00565 00566 if ((schema->doc != NULL) && (!(schema->preserve))) 00567 xmlFreeDoc(schema->doc); 00568 00569 if (schema->namespaces != NULL) 00570 xmlFree((char **) schema->namespaces); 00571 00572 xmlSchematronFreeRules(schema->rules); 00573 xmlSchematronFreePatterns(schema->patterns); 00574 xmlDictFree(schema->dict); 00575 xmlFree(schema); 00576 } 00577 00587 xmlSchematronParserCtxtPtr 00588 xmlSchematronNewParserCtxt(const char *URL) 00589 { 00590 xmlSchematronParserCtxtPtr ret; 00591 00592 if (URL == NULL) 00593 return (NULL); 00594 00595 ret = 00596 (xmlSchematronParserCtxtPtr) 00597 xmlMalloc(sizeof(xmlSchematronParserCtxt)); 00598 if (ret == NULL) { 00599 xmlSchematronPErrMemory(NULL, "allocating schema parser context", 00600 NULL); 00601 return (NULL); 00602 } 00603 memset(ret, 0, sizeof(xmlSchematronParserCtxt)); 00604 ret->type = XML_STRON_CTXT_PARSER; 00605 ret->dict = xmlDictCreate(); 00606 ret->URL = xmlDictLookup(ret->dict, (const xmlChar *) URL, -1); 00607 ret->includes = NULL; 00608 ret->xctxt = xmlXPathNewContext(NULL); 00609 if (ret->xctxt == NULL) { 00610 xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context", 00611 NULL); 00612 xmlSchematronFreeParserCtxt(ret); 00613 return (NULL); 00614 } 00615 ret->xctxt->flags = XML_XPATH_CHECKNS; 00616 return (ret); 00617 } 00618 00629 xmlSchematronParserCtxtPtr 00630 xmlSchematronNewMemParserCtxt(const char *buffer, int size) 00631 { 00632 xmlSchematronParserCtxtPtr ret; 00633 00634 if ((buffer == NULL) || (size <= 0)) 00635 return (NULL); 00636 00637 ret = 00638 (xmlSchematronParserCtxtPtr) 00639 xmlMalloc(sizeof(xmlSchematronParserCtxt)); 00640 if (ret == NULL) { 00641 xmlSchematronPErrMemory(NULL, "allocating schema parser context", 00642 NULL); 00643 return (NULL); 00644 } 00645 memset(ret, 0, sizeof(xmlSchematronParserCtxt)); 00646 ret->buffer = buffer; 00647 ret->size = size; 00648 ret->dict = xmlDictCreate(); 00649 ret->xctxt = xmlXPathNewContext(NULL); 00650 if (ret->xctxt == NULL) { 00651 xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context", 00652 NULL); 00653 xmlSchematronFreeParserCtxt(ret); 00654 return (NULL); 00655 } 00656 return (ret); 00657 } 00658 00668 xmlSchematronParserCtxtPtr 00669 xmlSchematronNewDocParserCtxt(xmlDocPtr doc) 00670 { 00671 xmlSchematronParserCtxtPtr ret; 00672 00673 if (doc == NULL) 00674 return (NULL); 00675 00676 ret = 00677 (xmlSchematronParserCtxtPtr) 00678 xmlMalloc(sizeof(xmlSchematronParserCtxt)); 00679 if (ret == NULL) { 00680 xmlSchematronPErrMemory(NULL, "allocating schema parser context", 00681 NULL); 00682 return (NULL); 00683 } 00684 memset(ret, 0, sizeof(xmlSchematronParserCtxt)); 00685 ret->doc = doc; 00686 ret->dict = xmlDictCreate(); 00687 /* The application has responsibility for the document */ 00688 ret->preserve = 1; 00689 ret->xctxt = xmlXPathNewContext(doc); 00690 if (ret->xctxt == NULL) { 00691 xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context", 00692 NULL); 00693 xmlSchematronFreeParserCtxt(ret); 00694 return (NULL); 00695 } 00696 00697 return (ret); 00698 } 00699 00706 void 00707 xmlSchematronFreeParserCtxt(xmlSchematronParserCtxtPtr ctxt) 00708 { 00709 if (ctxt == NULL) 00710 return; 00711 if (ctxt->doc != NULL && !ctxt->preserve) 00712 xmlFreeDoc(ctxt->doc); 00713 if (ctxt->xctxt != NULL) { 00714 xmlXPathFreeContext(ctxt->xctxt); 00715 } 00716 if (ctxt->namespaces != NULL) 00717 xmlFree((char **) ctxt->namespaces); 00718 xmlDictFree(ctxt->dict); 00719 xmlFree(ctxt); 00720 } 00721 00722 #if 0 00723 00731 static void 00732 xmlSchematronPushInclude(xmlSchematronParserCtxtPtr ctxt, 00733 xmlDocPtr doc, xmlNodePtr cur) 00734 { 00735 if (ctxt->includes == NULL) { 00736 ctxt->maxIncludes = 10; 00737 ctxt->includes = (xmlNodePtr *) 00738 xmlMalloc(ctxt->maxIncludes * 2 * sizeof(xmlNodePtr)); 00739 if (ctxt->includes == NULL) { 00740 xmlSchematronPErrMemory(NULL, "allocating parser includes", 00741 NULL); 00742 return; 00743 } 00744 ctxt->nbIncludes = 0; 00745 } else if (ctxt->nbIncludes + 2 >= ctxt->maxIncludes) { 00746 xmlNodePtr *tmp; 00747 00748 tmp = (xmlNodePtr *) 00749 xmlRealloc(ctxt->includes, ctxt->maxIncludes * 4 * 00750 sizeof(xmlNodePtr)); 00751 if (tmp == NULL) { 00752 xmlSchematronPErrMemory(NULL, "allocating parser includes", 00753 NULL); 00754 return; 00755 } 00756 ctxt->includes = tmp; 00757 ctxt->maxIncludes *= 2; 00758 } 00759 ctxt->includes[2 * ctxt->nbIncludes] = cur; 00760 ctxt->includes[2 * ctxt->nbIncludes + 1] = (xmlNodePtr) doc; 00761 ctxt->nbIncludes++; 00762 } 00763 00773 static xmlNodePtr 00774 xmlSchematronPopInclude(xmlSchematronParserCtxtPtr ctxt) 00775 { 00776 xmlDocPtr doc; 00777 xmlNodePtr ret; 00778 00779 if (ctxt->nbIncludes <= 0) 00780 return(NULL); 00781 ctxt->nbIncludes--; 00782 doc = (xmlDocPtr) ctxt->includes[2 * ctxt->nbIncludes + 1]; 00783 ret = ctxt->includes[2 * ctxt->nbIncludes]; 00784 xmlFreeDoc(doc); 00785 if (ret != NULL) 00786 ret = ret->next; 00787 if (ret == NULL) 00788 return(xmlSchematronPopInclude(ctxt)); 00789 return(ret); 00790 } 00791 #endif 00792 00801 static void 00802 xmlSchematronAddNamespace(xmlSchematronParserCtxtPtr ctxt, 00803 const xmlChar *prefix, const xmlChar *ns) 00804 { 00805 if (ctxt->namespaces == NULL) { 00806 ctxt->maxNamespaces = 10; 00807 ctxt->namespaces = (const xmlChar **) 00808 xmlMalloc(ctxt->maxNamespaces * 2 * sizeof(const xmlChar *)); 00809 if (ctxt->namespaces == NULL) { 00810 xmlSchematronPErrMemory(NULL, "allocating parser namespaces", 00811 NULL); 00812 return; 00813 } 00814 ctxt->nbNamespaces = 0; 00815 } else if (ctxt->nbNamespaces + 2 >= ctxt->maxNamespaces) { 00816 const xmlChar **tmp; 00817 00818 tmp = (const xmlChar **) 00819 xmlRealloc((xmlChar **) ctxt->namespaces, ctxt->maxNamespaces * 4 * 00820 sizeof(const xmlChar *)); 00821 if (tmp == NULL) { 00822 xmlSchematronPErrMemory(NULL, "allocating parser namespaces", 00823 NULL); 00824 return; 00825 } 00826 ctxt->namespaces = tmp; 00827 ctxt->maxNamespaces *= 2; 00828 } 00829 ctxt->namespaces[2 * ctxt->nbNamespaces] = 00830 xmlDictLookup(ctxt->dict, ns, -1); 00831 ctxt->namespaces[2 * ctxt->nbNamespaces + 1] = 00832 xmlDictLookup(ctxt->dict, prefix, -1); 00833 ctxt->nbNamespaces++; 00834 ctxt->namespaces[2 * ctxt->nbNamespaces] = NULL; 00835 ctxt->namespaces[2 * ctxt->nbNamespaces + 1] = NULL; 00836 00837 } 00838 00846 static void 00847 xmlSchematronParseRule(xmlSchematronParserCtxtPtr ctxt, 00848 xmlSchematronPatternPtr pattern, 00849 xmlNodePtr rule) 00850 { 00851 xmlNodePtr cur; 00852 int nbChecks = 0; 00853 xmlChar *test; 00854 xmlChar *context; 00855 xmlChar *report; 00856 xmlSchematronRulePtr ruleptr; 00857 xmlSchematronTestPtr testptr; 00858 00859 if ((ctxt == NULL) || (rule == NULL)) return; 00860 00861 context = xmlGetNoNsProp(rule, BAD_CAST "context"); 00862 if (context == NULL) { 00863 xmlSchematronPErr(ctxt, rule, 00864 XML_SCHEMAP_NOROOT, 00865 "rule has no context attribute", 00866 NULL, NULL); 00867 return; 00868 } else if (context[0] == 0) { 00869 xmlSchematronPErr(ctxt, rule, 00870 XML_SCHEMAP_NOROOT, 00871 "rule has an empty context attribute", 00872 NULL, NULL); 00873 xmlFree(context); 00874 return; 00875 } else { 00876 ruleptr = xmlSchematronAddRule(ctxt, ctxt->schema, pattern, 00877 rule, context, NULL); 00878 if (ruleptr == NULL) { 00879 xmlFree(context); 00880 return; 00881 } 00882 } 00883 00884 cur = rule->children; 00885 NEXT_SCHEMATRON(cur); 00886 while (cur != NULL) { 00887 if (IS_SCHEMATRON(cur, "assert")) { 00888 nbChecks++; 00889 test = xmlGetNoNsProp(cur, BAD_CAST "test"); 00890 if (test == NULL) { 00891 xmlSchematronPErr(ctxt, cur, 00892 XML_SCHEMAP_NOROOT, 00893 "assert has no test attribute", 00894 NULL, NULL); 00895 } else if (test[0] == 0) { 00896 xmlSchematronPErr(ctxt, cur, 00897 XML_SCHEMAP_NOROOT, 00898 "assert has an empty test attribute", 00899 NULL, NULL); 00900 xmlFree(test); 00901 } else { 00902 /* TODO will need dynamic processing instead */ 00903 report = xmlNodeGetContent(cur); 00904 00905 testptr = xmlSchematronAddTest(ctxt, XML_SCHEMATRON_ASSERT, 00906 ruleptr, cur, test, report); 00907 if (testptr == NULL) 00908 xmlFree(test); 00909 } 00910 } else if (IS_SCHEMATRON(cur, "report")) { 00911 nbChecks++; 00912 test = xmlGetNoNsProp(cur, BAD_CAST "test"); 00913 if (test == NULL) { 00914 xmlSchematronPErr(ctxt, cur, 00915 XML_SCHEMAP_NOROOT, 00916 "assert has no test attribute", 00917 NULL, NULL); 00918 } else if (test[0] == 0) { 00919 xmlSchematronPErr(ctxt, cur, 00920 XML_SCHEMAP_NOROOT, 00921 "assert has an empty test attribute", 00922 NULL, NULL); 00923 xmlFree(test); 00924 } else { 00925 /* TODO will need dynamic processing instead */ 00926 report = xmlNodeGetContent(cur); 00927 00928 testptr = xmlSchematronAddTest(ctxt, XML_SCHEMATRON_REPORT, 00929 ruleptr, cur, test, report); 00930 if (testptr == NULL) 00931 xmlFree(test); 00932 } 00933 } else { 00934 xmlSchematronPErr(ctxt, cur, 00935 XML_SCHEMAP_NOROOT, 00936 "Expecting an assert or a report element instead of %s", 00937 cur->name, NULL); 00938 } 00939 cur = cur->next; 00940 NEXT_SCHEMATRON(cur); 00941 } 00942 if (nbChecks == 0) { 00943 xmlSchematronPErr(ctxt, rule, 00944 XML_SCHEMAP_NOROOT, 00945 "rule has no assert nor report element", NULL, NULL); 00946 } 00947 } 00948 00956 static void 00957 xmlSchematronParsePattern(xmlSchematronParserCtxtPtr ctxt, xmlNodePtr pat) 00958 { 00959 xmlNodePtr cur; 00960 xmlSchematronPatternPtr pattern; 00961 int nbRules = 0; 00962 xmlChar *id; 00963 00964 if ((ctxt == NULL) || (pat == NULL)) return; 00965 00966 id = xmlGetNoNsProp(pat, BAD_CAST "id"); 00967 if (id == NULL) { 00968 id = xmlGetNoNsProp(pat, BAD_CAST "name"); 00969 } 00970 pattern = xmlSchematronAddPattern(ctxt, ctxt->schema, pat, id); 00971 if (pattern == NULL) { 00972 if (id != NULL) 00973 xmlFree(id); 00974 return; 00975 } 00976 cur = pat->children; 00977 NEXT_SCHEMATRON(cur); 00978 while (cur != NULL) { 00979 if (IS_SCHEMATRON(cur, "rule")) { 00980 xmlSchematronParseRule(ctxt, pattern, cur); 00981 nbRules++; 00982 } else { 00983 xmlSchematronPErr(ctxt, cur, 00984 XML_SCHEMAP_NOROOT, 00985 "Expecting a rule element instead of %s", cur->name, NULL); 00986 } 00987 cur = cur->next; 00988 NEXT_SCHEMATRON(cur); 00989 } 00990 if (nbRules == 0) { 00991 xmlSchematronPErr(ctxt, pat, 00992 XML_SCHEMAP_NOROOT, 00993 "Pattern has no rule element", NULL, NULL); 00994 } 00995 } 00996 00997 #if 0 00998 01007 static xmlNodePtr 01008 xmlSchematronLoadInclude(xmlSchematronParserCtxtPtr ctxt, xmlNodePtr cur) 01009 { 01010 xmlNodePtr ret = NULL; 01011 xmlDocPtr doc = NULL; 01012 xmlChar *href = NULL; 01013 xmlChar *base = NULL; 01014 xmlChar *URI = NULL; 01015 01016 if ((ctxt == NULL) || (cur == NULL)) 01017 return(NULL); 01018 01019 href = xmlGetNoNsProp(cur, BAD_CAST "href"); 01020 if (href == NULL) { 01021 xmlSchematronPErr(ctxt, cur, 01022 XML_SCHEMAP_NOROOT, 01023 "Include has no href attribute", NULL, NULL); 01024 return(cur->next); 01025 } 01026 01027 /* do the URI base composition, load and find the root */ 01028 base = xmlNodeGetBase(cur->doc, cur); 01029 URI = xmlBuildURI(href, base); 01030 doc = xmlReadFile((const char *) URI, NULL, SCHEMATRON_PARSE_OPTIONS); 01031 if (doc == NULL) { 01032 xmlSchematronPErr(ctxt, cur, 01033 XML_SCHEMAP_FAILED_LOAD, 01034 "could not load include '%s'.\n", 01035 URI, NULL); 01036 goto done; 01037 } 01038 ret = xmlDocGetRootElement(doc); 01039 if (ret == NULL) { 01040 xmlSchematronPErr(ctxt, cur, 01041 XML_SCHEMAP_FAILED_LOAD, 01042 "could not find root from include '%s'.\n", 01043 URI, NULL); 01044 goto done; 01045 } 01046 01047 /* Success, push the include for rollback on exit */ 01048 xmlSchematronPushInclude(ctxt, doc, cur); 01049 01050 done: 01051 if (ret == NULL) { 01052 if (doc != NULL) 01053 xmlFreeDoc(doc); 01054 } 01055 xmlFree(href); 01056 if (base != NULL) 01057 xmlFree(base); 01058 if (URI != NULL) 01059 xmlFree(URI); 01060 return(ret); 01061 } 01062 #endif 01063 01074 xmlSchematronPtr 01075 xmlSchematronParse(xmlSchematronParserCtxtPtr ctxt) 01076 { 01077 xmlSchematronPtr ret = NULL; 01078 xmlDocPtr doc; 01079 xmlNodePtr root, cur; 01080 int preserve = 0; 01081 01082 if (ctxt == NULL) 01083 return (NULL); 01084 01085 ctxt->nberrors = 0; 01086 01087 /* 01088 * First step is to parse the input document into an DOM/Infoset 01089 */ 01090 if (ctxt->URL != NULL) { 01091 doc = xmlReadFile((const char *) ctxt->URL, NULL, 01092 SCHEMATRON_PARSE_OPTIONS); 01093 if (doc == NULL) { 01094 xmlSchematronPErr(ctxt, NULL, 01095 XML_SCHEMAP_FAILED_LOAD, 01096 "xmlSchematronParse: could not load '%s'.\n", 01097 ctxt->URL, NULL); 01098 return (NULL); 01099 } 01100 ctxt->preserve = 0; 01101 } else if (ctxt->buffer != NULL) { 01102 doc = xmlReadMemory(ctxt->buffer, ctxt->size, NULL, NULL, 01103 SCHEMATRON_PARSE_OPTIONS); 01104 if (doc == NULL) { 01105 xmlSchematronPErr(ctxt, NULL, 01106 XML_SCHEMAP_FAILED_PARSE, 01107 "xmlSchematronParse: could not parse.\n", 01108 NULL, NULL); 01109 return (NULL); 01110 } 01111 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer"); 01112 ctxt->URL = xmlDictLookup(ctxt->dict, BAD_CAST "in_memory_buffer", -1); 01113 ctxt->preserve = 0; 01114 } else if (ctxt->doc != NULL) { 01115 doc = ctxt->doc; 01116 preserve = 1; 01117 ctxt->preserve = 1; 01118 } else { 01119 xmlSchematronPErr(ctxt, NULL, 01120 XML_SCHEMAP_NOTHING_TO_PARSE, 01121 "xmlSchematronParse: could not parse.\n", 01122 NULL, NULL); 01123 return (NULL); 01124 } 01125 01126 /* 01127 * Then extract the root and Schematron parse it 01128 */ 01129 root = xmlDocGetRootElement(doc); 01130 if (root == NULL) { 01131 xmlSchematronPErr(ctxt, (xmlNodePtr) doc, 01132 XML_SCHEMAP_NOROOT, 01133 "The schema has no document element.\n", NULL, NULL); 01134 if (!preserve) { 01135 xmlFreeDoc(doc); 01136 } 01137 return (NULL); 01138 } 01139 01140 if (!IS_SCHEMATRON(root, "schema")) { 01141 xmlSchematronPErr(ctxt, root, 01142 XML_SCHEMAP_NOROOT, 01143 "The XML document '%s' is not a XML schematron document", 01144 ctxt->URL, NULL); 01145 goto exit; 01146 } 01147 ret = xmlSchematronNewSchematron(ctxt); 01148 if (ret == NULL) 01149 goto exit; 01150 ctxt->schema = ret; 01151 01152 /* 01153 * scan the schema elements 01154 */ 01155 cur = root->children; 01156 NEXT_SCHEMATRON(cur); 01157 if (IS_SCHEMATRON(cur, "title")) { 01158 xmlChar *title = xmlNodeGetContent(cur); 01159 if (title != NULL) { 01160 ret->title = xmlDictLookup(ret->dict, title, -1); 01161 xmlFree(title); 01162 } 01163 cur = cur->next; 01164 NEXT_SCHEMATRON(cur); 01165 } 01166 while (IS_SCHEMATRON(cur, "ns")) { 01167 xmlChar *prefix = xmlGetNoNsProp(cur, BAD_CAST "prefix"); 01168 xmlChar *uri = xmlGetNoNsProp(cur, BAD_CAST "uri"); 01169 if ((uri == NULL) || (uri[0] == 0)) { 01170 xmlSchematronPErr(ctxt, cur, 01171 XML_SCHEMAP_NOROOT, 01172 "ns element has no uri", NULL, NULL); 01173 } 01174 if ((prefix == NULL) || (prefix[0] == 0)) { 01175 xmlSchematronPErr(ctxt, cur, 01176 XML_SCHEMAP_NOROOT, 01177 "ns element has no prefix", NULL, NULL); 01178 } 01179 if ((prefix) && (uri)) { 01180 xmlXPathRegisterNs(ctxt->xctxt, prefix, uri); 01181 xmlSchematronAddNamespace(ctxt, prefix, uri); 01182 ret->nbNs++; 01183 } 01184 if (uri) 01185 xmlFree(uri); 01186 if (prefix) 01187 xmlFree(prefix); 01188 cur = cur->next; 01189 NEXT_SCHEMATRON(cur); 01190 } 01191 while (cur != NULL) { 01192 if (IS_SCHEMATRON(cur, "pattern")) { 01193 xmlSchematronParsePattern(ctxt, cur); 01194 ret->nbPattern++; 01195 } else { 01196 xmlSchematronPErr(ctxt, cur, 01197 XML_SCHEMAP_NOROOT, 01198 "Expecting a pattern element instead of %s", cur->name, NULL); 01199 } 01200 cur = cur->next; 01201 NEXT_SCHEMATRON(cur); 01202 } 01203 if (ret->nbPattern == 0) { 01204 xmlSchematronPErr(ctxt, root, 01205 XML_SCHEMAP_NOROOT, 01206 "The schematron document '%s' has no pattern", 01207 ctxt->URL, NULL); 01208 goto exit; 01209 } 01210 /* the original document must be kept for reporting */ 01211 ret->doc = doc; 01212 if (preserve) { 01213 ret->preserve = 1; 01214 } 01215 preserve = 1; 01216 01217 exit: 01218 if (!preserve) { 01219 xmlFreeDoc(doc); 01220 } 01221 if (ret != NULL) { 01222 if (ctxt->nberrors != 0) { 01223 xmlSchematronFree(ret); 01224 ret = NULL; 01225 } else { 01226 ret->namespaces = ctxt->namespaces; 01227 ret->nbNamespaces = ctxt->nbNamespaces; 01228 ctxt->namespaces = NULL; 01229 } 01230 } 01231 return (ret); 01232 } 01233 01234 /************************************************************************ 01235 * * 01236 * Schematrontron Reports handler * 01237 * * 01238 ************************************************************************/ 01239 01240 static xmlNodePtr 01241 xmlSchematronGetNode(xmlSchematronValidCtxtPtr ctxt, 01242 xmlNodePtr cur, const xmlChar *xpath) { 01243 xmlNodePtr node = NULL; 01244 xmlXPathObjectPtr ret; 01245 01246 if ((ctxt == NULL) || (cur == NULL) || (xpath == NULL)) 01247 return(NULL); 01248 01249 ctxt->xctxt->doc = cur->doc; 01250 ctxt->xctxt->node = cur; 01251 ret = xmlXPathEval(xpath, ctxt->xctxt); 01252 if (ret == NULL) 01253 return(NULL); 01254 01255 if ((ret->type == XPATH_NODESET) && 01256 (ret->nodesetval != NULL) && (ret->nodesetval->nodeNr > 0)) 01257 node = ret->nodesetval->nodeTab[0]; 01258 01259 xmlXPathFreeObject(ret); 01260 return(node); 01261 } 01262 01271 static void 01272 xmlSchematronReportOutput(xmlSchematronValidCtxtPtr ctxt ATTRIBUTE_UNUSED, 01273 xmlNodePtr cur ATTRIBUTE_UNUSED, 01274 const char *msg) { 01275 /* TODO */ 01276 fprintf(stderr, "%s", msg); 01277 } 01278 01290 static xmlChar * 01291 xmlSchematronFormatReport(xmlSchematronValidCtxtPtr ctxt, 01292 xmlNodePtr test, xmlNodePtr cur) { 01293 xmlChar *ret = NULL; 01294 xmlNodePtr child, node; 01295 01296 if ((test == NULL) || (cur == NULL)) 01297 return(ret); 01298 01299 child = test->children; 01300 while (child != NULL) { 01301 if ((child->type == XML_TEXT_NODE) || 01302 (child->type == XML_CDATA_SECTION_NODE)) 01303 ret = xmlStrcat(ret, child->content); 01304 else if (IS_SCHEMATRON(child, "name")) { 01305 xmlChar *path; 01306 01307 path = xmlGetNoNsProp(child, BAD_CAST "path"); 01308 01309 node = cur; 01310 if (path != NULL) { 01311 node = xmlSchematronGetNode(ctxt, cur, path); 01312 if (node == NULL) 01313 node = cur; 01314 xmlFree(path); 01315 } 01316 01317 if ((node->ns == NULL) || (node->ns->prefix == NULL)) 01318 ret = xmlStrcat(ret, node->name); 01319 else { 01320 ret = xmlStrcat(ret, node->ns->prefix); 01321 ret = xmlStrcat(ret, BAD_CAST ":"); 01322 ret = xmlStrcat(ret, node->name); 01323 } 01324 } else { 01325 child = child->next; 01326 continue; 01327 } 01328 01329 /* 01330 * remove superfluous \n 01331 */ 01332 if (ret != NULL) { 01333 int len = xmlStrlen(ret); 01334 xmlChar c; 01335 01336 if (len > 0) { 01337 c = ret[len - 1]; 01338 if ((c == ' ') || (c == '\n') || (c == '\r') || (c == '\t')) { 01339 while ((c == ' ') || (c == '\n') || 01340 (c == '\r') || (c == '\t')) { 01341 len--; 01342 if (len == 0) 01343 break; 01344 c = ret[len - 1]; 01345 } 01346 ret[len] = ' '; 01347 ret[len + 1] = 0; 01348 } 01349 } 01350 } 01351 01352 child = child->next; 01353 } 01354 return(ret); 01355 } 01356 01367 static void 01368 xmlSchematronReportSuccess(xmlSchematronValidCtxtPtr ctxt, 01369 xmlSchematronTestPtr test, xmlNodePtr cur, xmlSchematronPatternPtr pattern, int success) { 01370 if ((ctxt == NULL) || (cur == NULL) || (test == NULL)) 01371 return; 01372 /* if quiet and not SVRL report only failures */ 01373 if ((ctxt->flags & XML_SCHEMATRON_OUT_QUIET) && 01374 ((ctxt->flags & XML_SCHEMATRON_OUT_XML) == 0) && 01375 (test->type == XML_SCHEMATRON_REPORT)) 01376 return; 01377 if (ctxt->flags & XML_SCHEMATRON_OUT_XML) { 01378 TODO 01379 } else { 01380 xmlChar *path; 01381 char msg[1000]; 01382 long line; 01383 const xmlChar *report = NULL; 01384 01385 if (((test->type == XML_SCHEMATRON_REPORT) & (!success)) || 01386 ((test->type == XML_SCHEMATRON_ASSERT) & (success))) 01387 return; 01388 line = xmlGetLineNo(cur); 01389 path = xmlGetNodePath(cur); 01390 if (path == NULL) 01391 path = (xmlChar *) cur->name; 01392 #if 0 01393 if ((test->report != NULL) && (test->report[0] != 0)) 01394 report = test->report; 01395 #endif 01396 if (test->node != NULL) 01397 report = xmlSchematronFormatReport(ctxt, test->node, cur); 01398 if (report == NULL) { 01399 if (test->type == XML_SCHEMATRON_ASSERT) { 01400 report = xmlStrdup((const xmlChar *) "node failed assert"); 01401 } else { 01402 report = xmlStrdup((const xmlChar *) "node failed report"); 01403 } 01404 } 01405 snprintf(msg, 999, "%s line %ld: %s\n", (const char *) path, 01406 line, (const char *) report); 01407 01408 if (ctxt->flags & XML_SCHEMATRON_OUT_ERROR) { 01409 xmlStructuredErrorFunc schannel = NULL; 01410 xmlGenericErrorFunc channel = NULL; 01411 void *data = NULL; 01412 01413 if (ctxt != NULL) { 01414 if (ctxt->serror != NULL) 01415 schannel = ctxt->serror; 01416 else 01417 channel = ctxt->error; 01418 data = ctxt->userData; 01419 } 01420 01421 __xmlRaiseError(schannel, channel, data, 01422 NULL, cur, XML_FROM_SCHEMATRONV, 01423 (test->type == XML_SCHEMATRON_ASSERT)?XML_SCHEMATRONV_ASSERT:XML_SCHEMATRONV_REPORT, 01424 XML_ERR_ERROR, NULL, line, 01425 (pattern == NULL)?NULL:((const char *) pattern->name), 01426 (const char *) path, 01427 (const char *) report, 0, 0, 01428 "%s", msg); 01429 } else { 01430 xmlSchematronReportOutput(ctxt, cur, &msg[0]); 01431 } 01432 01433 xmlFree((char *) report); 01434 01435 if ((path != NULL) && (path != (xmlChar *) cur->name)) 01436 xmlFree(path); 01437 } 01438 } 01439 01447 static void 01448 xmlSchematronReportPattern(xmlSchematronValidCtxtPtr ctxt, 01449 xmlSchematronPatternPtr pattern) { 01450 if ((ctxt == NULL) || (pattern == NULL)) 01451 return; 01452 if ((ctxt->flags & XML_SCHEMATRON_OUT_QUIET) || (ctxt->flags & XML_SCHEMATRON_OUT_ERROR)) /* Error gives pattern name as part of error */ 01453 return; 01454 if (ctxt->flags & XML_SCHEMATRON_OUT_XML) { 01455 TODO 01456 } else { 01457 char msg[1000]; 01458 01459 if (pattern->name == NULL) 01460 return; 01461 snprintf(msg, 999, "Pattern: %s\n", (const char *) pattern->name); 01462 xmlSchematronReportOutput(ctxt, NULL, &msg[0]); 01463 } 01464 } 01465 01466 01467 /************************************************************************ 01468 * * 01469 * Validation against a Schematrontron * 01470 * * 01471 ************************************************************************/ 01472 01481 void 01482 xmlSchematronSetValidStructuredErrors(xmlSchematronValidCtxtPtr ctxt, 01483 xmlStructuredErrorFunc serror, void *ctx) 01484 { 01485 if (ctxt == NULL) 01486 return; 01487 ctxt->serror = serror; 01488 ctxt->error = NULL; 01489 ctxt->warning = NULL; 01490 ctxt->userData = ctx; 01491 } 01492 01502 xmlSchematronValidCtxtPtr 01503 xmlSchematronNewValidCtxt(xmlSchematronPtr schema, int options) 01504 { 01505 int i; 01506 xmlSchematronValidCtxtPtr ret; 01507 01508 ret = (xmlSchematronValidCtxtPtr) xmlMalloc(sizeof(xmlSchematronValidCtxt)); 01509 if (ret == NULL) { 01510 xmlSchematronVErrMemory(NULL, "allocating validation context", 01511 NULL); 01512 return (NULL); 01513 } 01514 memset(ret, 0, sizeof(xmlSchematronValidCtxt)); 01515 ret->type = XML_STRON_CTXT_VALIDATOR; 01516 ret->schema = schema; 01517 ret->xctxt = xmlXPathNewContext(NULL); 01518 ret->flags = options; 01519 if (ret->xctxt == NULL) { 01520 xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context", 01521 NULL); 01522 xmlSchematronFreeValidCtxt(ret); 01523 return (NULL); 01524 } 01525 for (i = 0;i < schema->nbNamespaces;i++) { 01526 if ((schema->namespaces[2 * i] == NULL) || 01527 (schema->namespaces[2 * i + 1] == NULL)) 01528 break; 01529 xmlXPathRegisterNs(ret->xctxt, schema->namespaces[2 * i + 1], 01530 schema->namespaces[2 * i]); 01531 } 01532 return (ret); 01533 } 01534 01541 void 01542 xmlSchematronFreeValidCtxt(xmlSchematronValidCtxtPtr ctxt) 01543 { 01544 if (ctxt == NULL) 01545 return; 01546 if (ctxt->xctxt != NULL) 01547 xmlXPathFreeContext(ctxt->xctxt); 01548 if (ctxt->dict != NULL) 01549 xmlDictFree(ctxt->dict); 01550 xmlFree(ctxt); 01551 } 01552 01553 static xmlNodePtr 01554 xmlSchematronNextNode(xmlNodePtr cur) { 01555 if (cur->children != NULL) { 01556 /* 01557 * Do not descend on entities declarations 01558 */ 01559 if (cur->children->type != XML_ENTITY_DECL) { 01560 cur = cur->children; 01561 /* 01562 * Skip DTDs 01563 */ 01564 if (cur->type != XML_DTD_NODE) 01565 return(cur); 01566 } 01567 } 01568 01569 while (cur->next != NULL) { 01570 cur = cur->next; 01571 if ((cur->type != XML_ENTITY_DECL) && 01572 (cur->type != XML_DTD_NODE)) 01573 return(cur); 01574 } 01575 01576 do { 01577 cur = cur->parent; 01578 if (cur == NULL) break; 01579 if (cur->type == XML_DOCUMENT_NODE) return(NULL); 01580 if (cur->next != NULL) { 01581 cur = cur->next; 01582 return(cur); 01583 } 01584 } while (cur != NULL); 01585 return(cur); 01586 } 01587 01599 static int 01600 xmlSchematronRunTest(xmlSchematronValidCtxtPtr ctxt, 01601 xmlSchematronTestPtr test, xmlDocPtr instance, xmlNodePtr cur, xmlSchematronPatternPtr pattern) 01602 { 01603 xmlXPathObjectPtr ret; 01604 int failed; 01605 01606 failed = 0; 01607 ctxt->xctxt->doc = instance; 01608 ctxt->xctxt->node = cur; 01609 ret = xmlXPathCompiledEval(test->comp, ctxt->xctxt); 01610 if (ret == NULL) { 01611 failed = 1; 01612 } else { 01613 switch (ret->type) { 01614 case XPATH_XSLT_TREE: 01615 case XPATH_NODESET: 01616 if ((ret->nodesetval == NULL) || 01617 (ret->nodesetval->nodeNr == 0)) 01618 failed = 1; 01619 break; 01620 case XPATH_BOOLEAN: 01621 failed = !ret->boolval; 01622 break; 01623 case XPATH_NUMBER: 01624 if ((xmlXPathIsNaN(ret->floatval)) || 01625 (ret->floatval == 0.0)) 01626 failed = 1; 01627 break; 01628 case XPATH_STRING: 01629 if ((ret->stringval == NULL) || 01630 (ret->stringval[0] == 0)) 01631 failed = 1; 01632 break; 01633 case XPATH_UNDEFINED: 01634 case XPATH_POINT: 01635 case XPATH_RANGE: 01636 case XPATH_LOCATIONSET: 01637 case XPATH_USERS: 01638 failed = 1; 01639 break; 01640 } 01641 xmlXPathFreeObject(ret); 01642 } 01643 if ((failed) && (test->type == XML_SCHEMATRON_ASSERT)) 01644 ctxt->nberrors++; 01645 else if ((!failed) && (test->type == XML_SCHEMATRON_REPORT)) 01646 ctxt->nberrors++; 01647 01648 xmlSchematronReportSuccess(ctxt, test, cur, pattern, !failed); 01649 01650 return(!failed); 01651 } 01652 01663 int 01664 xmlSchematronValidateDoc(xmlSchematronValidCtxtPtr ctxt, xmlDocPtr instance) 01665 { 01666 xmlNodePtr cur, root; 01667 xmlSchematronPatternPtr pattern; 01668 xmlSchematronRulePtr rule; 01669 xmlSchematronTestPtr test; 01670 01671 if ((ctxt == NULL) || (ctxt->schema == NULL) || 01672 (ctxt->schema->rules == NULL) || (instance == NULL)) 01673 return(-1); 01674 ctxt->nberrors = 0; 01675 root = xmlDocGetRootElement(instance); 01676 if (root == NULL) { 01677 TODO 01678 ctxt->nberrors++; 01679 return(1); 01680 } 01681 if ((ctxt->flags & XML_SCHEMATRON_OUT_QUIET) || 01682 (ctxt->flags == 0)) { 01683 /* 01684 * we are just trying to assert the validity of the document, 01685 * speed primes over the output, run in a single pass 01686 */ 01687 cur = root; 01688 while (cur != NULL) { 01689 rule = ctxt->schema->rules; 01690 while (rule != NULL) { 01691 if (xmlPatternMatch(rule->pattern, cur) == 1) { 01692 test = rule->tests; 01693 while (test != NULL) { 01694 xmlSchematronRunTest(ctxt, test, instance, cur, (xmlSchematronPatternPtr)rule->pattern); 01695 test = test->next; 01696 } 01697 } 01698 rule = rule->next; 01699 } 01700 01701 cur = xmlSchematronNextNode(cur); 01702 } 01703 } else { 01704 /* 01705 * Process all contexts one at a time 01706 */ 01707 pattern = ctxt->schema->patterns; 01708 01709 while (pattern != NULL) { 01710 xmlSchematronReportPattern(ctxt, pattern); 01711 01712 /* 01713 * TODO convert the pattern rule to a direct XPath and 01714 * compute directly instead of using the pattern matching 01715 * over the full document... 01716 * Check the exact semantic 01717 */ 01718 cur = root; 01719 while (cur != NULL) { 01720 rule = pattern->rules; 01721 while (rule != NULL) { 01722 if (xmlPatternMatch(rule->pattern, cur) == 1) { 01723 test = rule->tests; 01724 while (test != NULL) { 01725 xmlSchematronRunTest(ctxt, test, instance, cur, pattern); 01726 test = test->next; 01727 } 01728 } 01729 rule = rule->patnext; 01730 } 01731 01732 cur = xmlSchematronNextNode(cur); 01733 } 01734 pattern = pattern->next; 01735 } 01736 } 01737 return(ctxt->nberrors); 01738 } 01739 01740 #ifdef STANDALONE 01741 int 01742 main(void) 01743 { 01744 int ret; 01745 xmlDocPtr instance; 01746 xmlSchematronParserCtxtPtr pctxt; 01747 xmlSchematronValidCtxtPtr vctxt; 01748 xmlSchematronPtr schema = NULL; 01749 01750 pctxt = xmlSchematronNewParserCtxt("tst.sct"); 01751 if (pctxt == NULL) { 01752 fprintf(stderr, "failed to build schematron parser\n"); 01753 } else { 01754 schema = xmlSchematronParse(pctxt); 01755 if (schema == NULL) { 01756 fprintf(stderr, "failed to compile schematron\n"); 01757 } 01758 xmlSchematronFreeParserCtxt(pctxt); 01759 } 01760 instance = xmlReadFile("tst.sct", NULL, 01761 XML_PARSE_NOENT | XML_PARSE_NOCDATA); 01762 if (instance == NULL) { 01763 fprintf(stderr, "failed to parse instance\n"); 01764 } 01765 if ((schema != NULL) && (instance != NULL)) { 01766 vctxt = xmlSchematronNewValidCtxt(schema); 01767 if (vctxt == NULL) { 01768 fprintf(stderr, "failed to build schematron validator\n"); 01769 } else { 01770 ret = xmlSchematronValidateDoc(vctxt, instance); 01771 xmlSchematronFreeValidCtxt(vctxt); 01772 } 01773 } 01774 xmlSchematronFree(schema); 01775 xmlFreeDoc(instance); 01776 01777 xmlCleanupParser(); 01778 xmlMemoryDump(); 01779 01780 return (0); 01781 } 01782 #endif 01783 #define bottom_schematron 01784 #include "elfgcchack.h" 01785 #endif /* LIBXML_SCHEMATRON_ENABLED */ Generated on Sun May 27 2012 04:34:33 for ReactOS by
1.7.6.1
|