ReactOS 0.4.15-dev-7918-g2a2556c
schematron.c
Go to the documentation of this file.
1/*
2 * schematron.c : implementation of the Schematron schema validity checking
3 *
4 * See Copyright for the status of this software.
5 *
6 * Daniel Veillard <daniel@veillard.com>
7 */
8
9/*
10 * TODO:
11 * + double check the semantic, especially
12 * - multiple rules applying in a single pattern/node
13 * - the semantic of libxml2 patterns vs. XSLT production referenced
14 * by the spec.
15 * + export of results in SVRL
16 * + full parsing and coverage of the spec, conformance of the input to the
17 * spec
18 * + divergences between the draft and the ISO proposed standard :-(
19 * + hook and test include
20 * + try and compare with the XSLT version
21 */
22
23#define IN_LIBXML
24#include "libxml.h"
25
26#ifdef LIBXML_SCHEMATRON_ENABLED
27
28#include <string.h>
29#include <libxml/parser.h>
30#include <libxml/tree.h>
31#include <libxml/uri.h>
32#include <libxml/xpath.h>
34#include <libxml/pattern.h>
35#include <libxml/schematron.h>
36
37#define SCHEMATRON_PARSE_OPTIONS XML_PARSE_NOENT
38
39#define SCT_OLD_NS BAD_CAST "http://www.ascc.net/xml/schematron"
40
41#define XML_SCHEMATRON_NS BAD_CAST "http://purl.oclc.org/dsdl/schematron"
42
43
44static const xmlChar *xmlSchematronNs = XML_SCHEMATRON_NS;
45static const xmlChar *xmlOldSchematronNs = SCT_OLD_NS;
46
47#define IS_SCHEMATRON(node, elem) \
48 ((node != NULL) && (node->type == XML_ELEMENT_NODE ) && \
49 (node->ns != NULL) && \
50 (xmlStrEqual(node->name, (const xmlChar *) elem)) && \
51 ((xmlStrEqual(node->ns->href, xmlSchematronNs)) || \
52 (xmlStrEqual(node->ns->href, xmlOldSchematronNs))))
53
54#define NEXT_SCHEMATRON(node) \
55 while (node != NULL) { \
56 if ((node->type == XML_ELEMENT_NODE ) && (node->ns != NULL) && \
57 ((xmlStrEqual(node->ns->href, xmlSchematronNs)) || \
58 (xmlStrEqual(node->ns->href, xmlOldSchematronNs)))) \
59 break; \
60 node = node->next; \
61 }
62
68#define TODO \
69 xmlGenericError(xmlGenericErrorContext, \
70 "Unimplemented block at %s:%d\n", \
71 __FILE__, __LINE__);
72
73typedef enum {
74 XML_SCHEMATRON_ASSERT=1,
75 XML_SCHEMATRON_REPORT=2
76} xmlSchematronTestType;
77
83typedef struct _xmlSchematronLet xmlSchematronLet;
84typedef xmlSchematronLet *xmlSchematronLetPtr;
85struct _xmlSchematronLet {
86 xmlSchematronLetPtr next; /* the next let variable in the list */
87 xmlChar *name; /* the name of the variable */
88 xmlXPathCompExprPtr comp; /* the compiled expression */
89};
90
96typedef struct _xmlSchematronTest xmlSchematronTest;
97typedef xmlSchematronTest *xmlSchematronTestPtr;
98struct _xmlSchematronTest {
99 xmlSchematronTestPtr next; /* the next test in the list */
100 xmlSchematronTestType type; /* the test type */
101 xmlNodePtr node; /* the node in the tree */
102 xmlChar *test; /* the expression to test */
103 xmlXPathCompExprPtr comp; /* the compiled expression */
104 xmlChar *report; /* the message to report */
105};
106
112typedef struct _xmlSchematronRule xmlSchematronRule;
113typedef xmlSchematronRule *xmlSchematronRulePtr;
114struct _xmlSchematronRule {
115 xmlSchematronRulePtr next; /* the next rule in the list */
116 xmlSchematronRulePtr patnext;/* the next rule in the pattern list */
117 xmlNodePtr node; /* the node in the tree */
118 xmlChar *context; /* the context evaluation rule */
119 xmlSchematronTestPtr tests; /* the list of tests */
120 xmlPatternPtr pattern; /* the compiled pattern associated */
121 xmlChar *report; /* the message to report */
122 xmlSchematronLetPtr lets; /* the list of let variables */
123};
124
130typedef struct _xmlSchematronPattern xmlSchematronPattern;
131typedef xmlSchematronPattern *xmlSchematronPatternPtr;
132struct _xmlSchematronPattern {
133 xmlSchematronPatternPtr next;/* the next pattern in the list */
134 xmlSchematronRulePtr rules; /* the list of rules */
135 xmlChar *name; /* the name of the pattern */
136};
137
143struct _xmlSchematron {
144 const xmlChar *name; /* schema name */
145 int preserve; /* was the document passed by the user */
146 xmlDocPtr doc; /* pointer to the parsed document */
147 int flags; /* specific to this schematron */
148
149 void *_private; /* unused by the library */
150 xmlDictPtr dict; /* the dictionary used internally */
151
152 const xmlChar *title; /* the title if any */
153
154 int nbNs; /* the number of namespaces */
155
156 int nbPattern; /* the number of patterns */
157 xmlSchematronPatternPtr patterns;/* the patterns found */
158 xmlSchematronRulePtr rules; /* the rules gathered */
159 int nbNamespaces; /* number of namespaces in the array */
160 int maxNamespaces; /* size of the array */
161 const xmlChar **namespaces; /* the array of namespaces */
162};
163
169struct _xmlSchematronValidCtxt {
170 int type;
171 int flags; /* an or of xmlSchematronValidOptions */
172
173 xmlDictPtr dict;
174 int nberrors;
175 int err;
176
177 xmlSchematronPtr schema;
178 xmlXPathContextPtr xctxt;
179
180 FILE *outputFile; /* if using XML_SCHEMATRON_OUT_FILE */
181 xmlBufferPtr outputBuffer; /* if using XML_SCHEMATRON_OUT_BUFFER */
182#ifdef LIBXML_OUTPUT_ENABLED
183 xmlOutputWriteCallback iowrite; /* if using XML_SCHEMATRON_OUT_IO */
184 xmlOutputCloseCallback ioclose;
185#endif
186 void *ioctx;
187
188 /* error reporting data */
189 void *userData; /* user specific data block */
190 xmlSchematronValidityErrorFunc error;/* the callback in case of errors */
191 xmlSchematronValidityWarningFunc warning;/* callback in case of warning */
192 xmlStructuredErrorFunc serror; /* the structured function */
193};
194
195struct _xmlSchematronParserCtxt {
196 int type;
197 const xmlChar *URL;
198 xmlDocPtr doc;
199 int preserve; /* Whether the doc should be freed */
200 const char *buffer;
201 int size;
202
203 xmlDictPtr dict; /* dictionary for interned string names */
204
205 int nberrors;
206 int err;
207 xmlXPathContextPtr xctxt; /* the XPath context used for compilation */
208 xmlSchematronPtr schema;
209
210 int nbNamespaces; /* number of namespaces in the array */
211 int maxNamespaces; /* size of the array */
212 const xmlChar **namespaces; /* the array of namespaces */
213
214 int nbIncludes; /* number of includes in the array */
215 int maxIncludes; /* size of the array */
216 xmlNodePtr *includes; /* the array of includes */
217
218 /* error reporting data */
219 void *userData; /* user specific data block */
220 xmlSchematronValidityErrorFunc error;/* the callback in case of errors */
221 xmlSchematronValidityWarningFunc warning;/* callback in case of warning */
222 xmlStructuredErrorFunc serror; /* the structured function */
223};
224
225#define XML_STRON_CTXT_PARSER 1
226#define XML_STRON_CTXT_VALIDATOR 2
227
228/************************************************************************
229 * *
230 * Error reporting *
231 * *
232 ************************************************************************/
233
241static void
242xmlSchematronPErrMemory(xmlSchematronParserCtxtPtr ctxt,
243 const char *extra, xmlNodePtr node)
244{
245 if (ctxt != NULL)
246 ctxt->nberrors++;
247 __xmlSimpleError(XML_FROM_SCHEMASP, XML_ERR_NO_MEMORY, node, NULL,
248 extra);
249}
250
262static void LIBXML_ATTR_FORMAT(4,0)
263xmlSchematronPErr(xmlSchematronParserCtxtPtr ctxt, xmlNodePtr node, int error,
264 const char *msg, const xmlChar * str1, const xmlChar * str2)
265{
266 xmlGenericErrorFunc channel = NULL;
267 xmlStructuredErrorFunc schannel = NULL;
268 void *data = NULL;
269
270 if (ctxt != NULL) {
271 ctxt->nberrors++;
272 channel = ctxt->error;
273 data = ctxt->userData;
274 schannel = ctxt->serror;
275 }
276 __xmlRaiseError(schannel, channel, data, ctxt, node, XML_FROM_SCHEMASP,
278 (const char *) str1, (const char *) str2, NULL, 0, 0,
279 msg, str1, str2);
280}
281
289static void
290xmlSchematronVErrMemory(xmlSchematronValidCtxtPtr ctxt,
291 const char *extra, xmlNodePtr node)
292{
293 if (ctxt != NULL) {
294 ctxt->nberrors++;
295 ctxt->err = XML_SCHEMAV_INTERNAL;
296 }
297 __xmlSimpleError(XML_FROM_SCHEMASV, XML_ERR_NO_MEMORY, node, NULL,
298 extra);
299}
300
301/************************************************************************
302 * *
303 * Parsing and compilation of the Schematrontrons *
304 * *
305 ************************************************************************/
306
320static xmlSchematronTestPtr
321xmlSchematronAddTest(xmlSchematronParserCtxtPtr ctxt,
322 xmlSchematronTestType type,
323 xmlSchematronRulePtr rule,
325{
326 xmlSchematronTestPtr ret;
327 xmlXPathCompExprPtr comp;
328
329 if ((ctxt == NULL) || (rule == NULL) || (node == NULL) ||
330 (test == NULL))
331 return(NULL);
332
333 /*
334 * try first to compile the test expression
335 */
336 comp = xmlXPathCtxtCompile(ctxt->xctxt, test);
337 if (comp == NULL) {
338 xmlSchematronPErr(ctxt, node,
340 "Failed to compile test expression %s",
341 test, NULL);
342 return(NULL);
343 }
344
345 ret = (xmlSchematronTestPtr) xmlMalloc(sizeof(xmlSchematronTest));
346 if (ret == NULL) {
347 xmlSchematronPErrMemory(ctxt, "allocating schema test", node);
348 return (NULL);
349 }
350 memset(ret, 0, sizeof(xmlSchematronTest));
351 ret->type = type;
352 ret->node = node;
353 ret->test = test;
354 ret->comp = comp;
355 ret->report = report;
356 ret->next = NULL;
357 if (rule->tests == NULL) {
358 rule->tests = ret;
359 } else {
360 xmlSchematronTestPtr prev = rule->tests;
361
362 while (prev->next != NULL)
363 prev = prev->next;
364 prev->next = ret;
365 }
366 return (ret);
367}
368
375static void
376xmlSchematronFreeTests(xmlSchematronTestPtr tests) {
377 xmlSchematronTestPtr next;
378
379 while (tests != NULL) {
380 next = tests->next;
381 if (tests->test != NULL)
382 xmlFree(tests->test);
383 if (tests->comp != NULL)
384 xmlXPathFreeCompExpr(tests->comp);
385 if (tests->report != NULL)
386 xmlFree(tests->report);
387 xmlFree(tests);
388 tests = next;
389 }
390}
391
398static void
399xmlSchematronFreeLets(xmlSchematronLetPtr lets) {
400 xmlSchematronLetPtr next;
401
402 while (lets != NULL) {
403 next = lets->next;
404 if (lets->name != NULL)
405 xmlFree(lets->name);
406 if (lets->comp != NULL)
407 xmlXPathFreeCompExpr(lets->comp);
408 xmlFree(lets);
409 lets = next;
410 }
411}
412
425static xmlSchematronRulePtr
426xmlSchematronAddRule(xmlSchematronParserCtxtPtr ctxt, xmlSchematronPtr schema,
427 xmlSchematronPatternPtr pat, xmlNodePtr node,
429{
430 xmlSchematronRulePtr ret;
431 xmlPatternPtr pattern;
432
433 if ((ctxt == NULL) || (schema == NULL) || (node == NULL) ||
434 (context == NULL))
435 return(NULL);
436
437 /*
438 * Try first to compile the pattern
439 */
440 pattern = xmlPatterncompile(context, ctxt->dict, XML_PATTERN_XPATH,
441 ctxt->namespaces);
442 if (pattern == NULL) {
443 xmlSchematronPErr(ctxt, node,
445 "Failed to compile context expression %s",
446 context, NULL);
447 }
448
449 ret = (xmlSchematronRulePtr) xmlMalloc(sizeof(xmlSchematronRule));
450 if (ret == NULL) {
451 xmlSchematronPErrMemory(ctxt, "allocating schema rule", node);
452 return (NULL);
453 }
454 memset(ret, 0, sizeof(xmlSchematronRule));
455 ret->node = node;
456 ret->context = context;
457 ret->pattern = pattern;
458 ret->report = report;
459 ret->next = NULL;
460 ret->lets = NULL;
461 if (schema->rules == NULL) {
462 schema->rules = ret;
463 } else {
464 xmlSchematronRulePtr prev = schema->rules;
465
466 while (prev->next != NULL)
467 prev = prev->next;
468 prev->next = ret;
469 }
470 ret->patnext = NULL;
471 if (pat->rules == NULL) {
472 pat->rules = ret;
473 } else {
474 xmlSchematronRulePtr prev = pat->rules;
475
476 while (prev->patnext != NULL)
477 prev = prev->patnext;
478 prev->patnext = ret;
479 }
480 return (ret);
481}
482
489static void
490xmlSchematronFreeRules(xmlSchematronRulePtr rules) {
491 xmlSchematronRulePtr next;
492
493 while (rules != NULL) {
494 next = rules->next;
495 if (rules->tests)
496 xmlSchematronFreeTests(rules->tests);
497 if (rules->context != NULL)
498 xmlFree(rules->context);
499 if (rules->pattern)
500 xmlFreePattern(rules->pattern);
501 if (rules->report != NULL)
502 xmlFree(rules->report);
503 if (rules->lets != NULL)
504 xmlSchematronFreeLets(rules->lets);
505 xmlFree(rules);
506 rules = next;
507 }
508}
509
521static xmlSchematronPatternPtr
522xmlSchematronAddPattern(xmlSchematronParserCtxtPtr ctxt,
523 xmlSchematronPtr schema, xmlNodePtr node, xmlChar *name)
524{
525 xmlSchematronPatternPtr ret;
526
527 if ((ctxt == NULL) || (schema == NULL) || (node == NULL) || (name == NULL))
528 return(NULL);
529
530 ret = (xmlSchematronPatternPtr) xmlMalloc(sizeof(xmlSchematronPattern));
531 if (ret == NULL) {
532 xmlSchematronPErrMemory(ctxt, "allocating schema pattern", node);
533 return (NULL);
534 }
535 memset(ret, 0, sizeof(xmlSchematronPattern));
536 ret->name = name;
537 ret->next = NULL;
538 if (schema->patterns == NULL) {
539 schema->patterns = ret;
540 } else {
541 xmlSchematronPatternPtr prev = schema->patterns;
542
543 while (prev->next != NULL)
544 prev = prev->next;
545 prev->next = ret;
546 }
547 return (ret);
548}
549
556static void
557xmlSchematronFreePatterns(xmlSchematronPatternPtr patterns) {
558 xmlSchematronPatternPtr next;
559
560 while (patterns != NULL) {
561 next = patterns->next;
562 if (patterns->name != NULL)
563 xmlFree(patterns->name);
564 xmlFree(patterns);
565 patterns = next;
566 }
567}
568
577static xmlSchematronPtr
578xmlSchematronNewSchematron(xmlSchematronParserCtxtPtr ctxt)
579{
580 xmlSchematronPtr ret;
581
582 ret = (xmlSchematronPtr) xmlMalloc(sizeof(xmlSchematron));
583 if (ret == NULL) {
584 xmlSchematronPErrMemory(ctxt, "allocating schema", NULL);
585 return (NULL);
586 }
587 memset(ret, 0, sizeof(xmlSchematron));
588 ret->dict = ctxt->dict;
589 xmlDictReference(ret->dict);
590
591 return (ret);
592}
593
600void
601xmlSchematronFree(xmlSchematronPtr schema)
602{
603 if (schema == NULL)
604 return;
605
606 if ((schema->doc != NULL) && (!(schema->preserve)))
607 xmlFreeDoc(schema->doc);
608
609 if (schema->namespaces != NULL)
610 xmlFree((char **) schema->namespaces);
611
612 xmlSchematronFreeRules(schema->rules);
613 xmlSchematronFreePatterns(schema->patterns);
614 xmlDictFree(schema->dict);
616}
617
627xmlSchematronParserCtxtPtr
628xmlSchematronNewParserCtxt(const char *URL)
629{
630 xmlSchematronParserCtxtPtr ret;
631
632 if (URL == NULL)
633 return (NULL);
634
635 ret =
636 (xmlSchematronParserCtxtPtr)
637 xmlMalloc(sizeof(xmlSchematronParserCtxt));
638 if (ret == NULL) {
639 xmlSchematronPErrMemory(NULL, "allocating schema parser context",
640 NULL);
641 return (NULL);
642 }
643 memset(ret, 0, sizeof(xmlSchematronParserCtxt));
644 ret->type = XML_STRON_CTXT_PARSER;
645 ret->dict = xmlDictCreate();
646 ret->URL = xmlDictLookup(ret->dict, (const xmlChar *) URL, -1);
647 ret->includes = NULL;
648 ret->xctxt = xmlXPathNewContext(NULL);
649 if (ret->xctxt == NULL) {
650 xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context",
651 NULL);
652 xmlSchematronFreeParserCtxt(ret);
653 return (NULL);
654 }
655 ret->xctxt->flags = XML_XPATH_CHECKNS;
656 return (ret);
657}
658
669xmlSchematronParserCtxtPtr
670xmlSchematronNewMemParserCtxt(const char *buffer, int size)
671{
672 xmlSchematronParserCtxtPtr ret;
673
674 if ((buffer == NULL) || (size <= 0))
675 return (NULL);
676
677 ret =
678 (xmlSchematronParserCtxtPtr)
679 xmlMalloc(sizeof(xmlSchematronParserCtxt));
680 if (ret == NULL) {
681 xmlSchematronPErrMemory(NULL, "allocating schema parser context",
682 NULL);
683 return (NULL);
684 }
685 memset(ret, 0, sizeof(xmlSchematronParserCtxt));
686 ret->buffer = buffer;
687 ret->size = size;
688 ret->dict = xmlDictCreate();
689 ret->xctxt = xmlXPathNewContext(NULL);
690 if (ret->xctxt == NULL) {
691 xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context",
692 NULL);
693 xmlSchematronFreeParserCtxt(ret);
694 return (NULL);
695 }
696 return (ret);
697}
698
708xmlSchematronParserCtxtPtr
709xmlSchematronNewDocParserCtxt(xmlDocPtr doc)
710{
711 xmlSchematronParserCtxtPtr ret;
712
713 if (doc == NULL)
714 return (NULL);
715
716 ret =
717 (xmlSchematronParserCtxtPtr)
718 xmlMalloc(sizeof(xmlSchematronParserCtxt));
719 if (ret == NULL) {
720 xmlSchematronPErrMemory(NULL, "allocating schema parser context",
721 NULL);
722 return (NULL);
723 }
724 memset(ret, 0, sizeof(xmlSchematronParserCtxt));
725 ret->doc = doc;
726 ret->dict = xmlDictCreate();
727 /* The application has responsibility for the document */
728 ret->preserve = 1;
729 ret->xctxt = xmlXPathNewContext(doc);
730 if (ret->xctxt == NULL) {
731 xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context",
732 NULL);
733 xmlSchematronFreeParserCtxt(ret);
734 return (NULL);
735 }
736
737 return (ret);
738}
739
746void
747xmlSchematronFreeParserCtxt(xmlSchematronParserCtxtPtr ctxt)
748{
749 if (ctxt == NULL)
750 return;
751 if (ctxt->doc != NULL && !ctxt->preserve)
752 xmlFreeDoc(ctxt->doc);
753 if (ctxt->xctxt != NULL) {
754 xmlXPathFreeContext(ctxt->xctxt);
755 }
756 if (ctxt->namespaces != NULL)
757 xmlFree((char **) ctxt->namespaces);
758 xmlDictFree(ctxt->dict);
759 xmlFree(ctxt);
760}
761
762#if 0
771static void
772xmlSchematronPushInclude(xmlSchematronParserCtxtPtr ctxt,
774{
775 if (ctxt->includes == NULL) {
776 ctxt->maxIncludes = 10;
777 ctxt->includes = (xmlNodePtr *)
778 xmlMalloc(ctxt->maxIncludes * 2 * sizeof(xmlNodePtr));
779 if (ctxt->includes == NULL) {
780 xmlSchematronPErrMemory(NULL, "allocating parser includes",
781 NULL);
782 return;
783 }
784 ctxt->nbIncludes = 0;
785 } else if (ctxt->nbIncludes + 2 >= ctxt->maxIncludes) {
786 xmlNodePtr *tmp;
787
788 tmp = (xmlNodePtr *)
789 xmlRealloc(ctxt->includes, ctxt->maxIncludes * 4 *
790 sizeof(xmlNodePtr));
791 if (tmp == NULL) {
792 xmlSchematronPErrMemory(NULL, "allocating parser includes",
793 NULL);
794 return;
795 }
796 ctxt->includes = tmp;
797 ctxt->maxIncludes *= 2;
798 }
799 ctxt->includes[2 * ctxt->nbIncludes] = cur;
800 ctxt->includes[2 * ctxt->nbIncludes + 1] = (xmlNodePtr) doc;
801 ctxt->nbIncludes++;
802}
803
813static xmlNodePtr
814xmlSchematronPopInclude(xmlSchematronParserCtxtPtr ctxt)
815{
816 xmlDocPtr doc;
818
819 if (ctxt->nbIncludes <= 0)
820 return(NULL);
821 ctxt->nbIncludes--;
822 doc = (xmlDocPtr) ctxt->includes[2 * ctxt->nbIncludes + 1];
823 ret = ctxt->includes[2 * ctxt->nbIncludes];
824 xmlFreeDoc(doc);
825 if (ret != NULL)
826 ret = ret->next;
827 if (ret == NULL)
828 return(xmlSchematronPopInclude(ctxt));
829 return(ret);
830}
831#endif
832
841static void
842xmlSchematronAddNamespace(xmlSchematronParserCtxtPtr ctxt,
843 const xmlChar *prefix, const xmlChar *ns)
844{
845 if (ctxt->namespaces == NULL) {
846 ctxt->maxNamespaces = 10;
847 ctxt->namespaces = (const xmlChar **)
848 xmlMalloc(ctxt->maxNamespaces * 2 * sizeof(const xmlChar *));
849 if (ctxt->namespaces == NULL) {
850 xmlSchematronPErrMemory(NULL, "allocating parser namespaces",
851 NULL);
852 return;
853 }
854 ctxt->nbNamespaces = 0;
855 } else if (ctxt->nbNamespaces + 2 >= ctxt->maxNamespaces) {
856 const xmlChar **tmp;
857
858 tmp = (const xmlChar **)
859 xmlRealloc((xmlChar **) ctxt->namespaces, ctxt->maxNamespaces * 4 *
860 sizeof(const xmlChar *));
861 if (tmp == NULL) {
862 xmlSchematronPErrMemory(NULL, "allocating parser namespaces",
863 NULL);
864 return;
865 }
866 ctxt->namespaces = tmp;
867 ctxt->maxNamespaces *= 2;
868 }
869 ctxt->namespaces[2 * ctxt->nbNamespaces] =
870 xmlDictLookup(ctxt->dict, ns, -1);
871 ctxt->namespaces[2 * ctxt->nbNamespaces + 1] =
872 xmlDictLookup(ctxt->dict, prefix, -1);
873 ctxt->nbNamespaces++;
874 ctxt->namespaces[2 * ctxt->nbNamespaces] = NULL;
875 ctxt->namespaces[2 * ctxt->nbNamespaces + 1] = NULL;
876
877}
878
886static void
887xmlSchematronParseTestReportMsg(xmlSchematronParserCtxtPtr ctxt, xmlNodePtr con)
888{
890 xmlXPathCompExprPtr comp;
891
892 child = con->children;
893 while (child != NULL) {
894 if ((child->type == XML_TEXT_NODE) ||
895 (child->type == XML_CDATA_SECTION_NODE))
896 /* Do Nothing */
897 {}
898 else if (IS_SCHEMATRON(child, "name")) {
899 /* Do Nothing */
900 } else if (IS_SCHEMATRON(child, "value-of")) {
902
903 select = xmlGetNoNsProp(child, BAD_CAST "select");
904
905 if (select == NULL) {
906 xmlSchematronPErr(ctxt, child,
908 "value-of has no select attribute",
909 NULL, NULL);
910 } else {
911 /*
912 * try first to compile the test expression
913 */
914 comp = xmlXPathCtxtCompile(ctxt->xctxt, select);
915 if (comp == NULL) {
916 xmlSchematronPErr(ctxt, child,
918 "Failed to compile select expression %s",
919 select, NULL);
920 }
921 xmlXPathFreeCompExpr(comp);
922 }
924 }
925 child = child->next;
926 continue;
927 }
928}
929
937static void
938xmlSchematronParseRule(xmlSchematronParserCtxtPtr ctxt,
939 xmlSchematronPatternPtr pattern,
940 xmlNodePtr rule)
941{
943 int nbChecks = 0;
944 xmlChar *test;
947 xmlChar *name;
948 xmlChar *value;
949 xmlSchematronRulePtr ruleptr;
950 xmlSchematronTestPtr testptr;
951
952 if ((ctxt == NULL) || (rule == NULL)) return;
953
954 context = xmlGetNoNsProp(rule, BAD_CAST "context");
955 if (context == NULL) {
956 xmlSchematronPErr(ctxt, rule,
958 "rule has no context attribute",
959 NULL, NULL);
960 return;
961 } else if (context[0] == 0) {
962 xmlSchematronPErr(ctxt, rule,
964 "rule has an empty context attribute",
965 NULL, NULL);
967 return;
968 } else {
969 ruleptr = xmlSchematronAddRule(ctxt, ctxt->schema, pattern,
970 rule, context, NULL);
971 if (ruleptr == NULL) {
973 return;
974 }
975 }
976
977 cur = rule->children;
978 NEXT_SCHEMATRON(cur);
979 while (cur != NULL) {
980 if (IS_SCHEMATRON(cur, "let")) {
981 xmlXPathCompExprPtr var_comp;
982 xmlSchematronLetPtr let;
983
984 name = xmlGetNoNsProp(cur, BAD_CAST "name");
985 if (name == NULL) {
986 xmlSchematronPErr(ctxt, cur,
988 "let has no name attribute",
989 NULL, NULL);
990 return;
991 } else if (name[0] == 0) {
992 xmlSchematronPErr(ctxt, cur,
994 "let has an empty name attribute",
995 NULL, NULL);
996 xmlFree(name);
997 return;
998 }
999 value = xmlGetNoNsProp(cur, BAD_CAST "value");
1000 if (value == NULL) {
1001 xmlSchematronPErr(ctxt, cur,
1003 "let has no value attribute",
1004 NULL, NULL);
1005 return;
1006 } else if (value[0] == 0) {
1007 xmlSchematronPErr(ctxt, cur,
1009 "let has an empty value attribute",
1010 NULL, NULL);
1011 xmlFree(value);
1012 return;
1013 }
1014
1015 var_comp = xmlXPathCtxtCompile(ctxt->xctxt, value);
1016 if (var_comp == NULL) {
1017 xmlSchematronPErr(ctxt, cur,
1019 "Failed to compile let expression %s",
1020 value, NULL);
1021 return;
1022 }
1023
1024 let = (xmlSchematronLetPtr) malloc(sizeof(xmlSchematronLet));
1025 let->name = name;
1026 let->comp = var_comp;
1027 let->next = NULL;
1028
1029 /* add new let variable to the beginning of the list */
1030 if (ruleptr->lets != NULL) {
1031 let->next = ruleptr->lets;
1032 }
1033 ruleptr->lets = let;
1034
1035 xmlFree(value);
1036 } else if (IS_SCHEMATRON(cur, "assert")) {
1037 nbChecks++;
1038 test = xmlGetNoNsProp(cur, BAD_CAST "test");
1039 if (test == NULL) {
1040 xmlSchematronPErr(ctxt, cur,
1042 "assert has no test attribute",
1043 NULL, NULL);
1044 } else if (test[0] == 0) {
1045 xmlSchematronPErr(ctxt, cur,
1047 "assert has an empty test attribute",
1048 NULL, NULL);
1049 xmlFree(test);
1050 } else {
1051 xmlSchematronParseTestReportMsg(ctxt, cur);
1053
1054 testptr = xmlSchematronAddTest(ctxt, XML_SCHEMATRON_ASSERT,
1055 ruleptr, cur, test, report);
1056 if (testptr == NULL)
1057 xmlFree(test);
1058 }
1059 } else if (IS_SCHEMATRON(cur, "report")) {
1060 nbChecks++;
1061 test = xmlGetNoNsProp(cur, BAD_CAST "test");
1062 if (test == NULL) {
1063 xmlSchematronPErr(ctxt, cur,
1065 "assert has no test attribute",
1066 NULL, NULL);
1067 } else if (test[0] == 0) {
1068 xmlSchematronPErr(ctxt, cur,
1070 "assert has an empty test attribute",
1071 NULL, NULL);
1072 xmlFree(test);
1073 } else {
1074 xmlSchematronParseTestReportMsg(ctxt, cur);
1076
1077 testptr = xmlSchematronAddTest(ctxt, XML_SCHEMATRON_REPORT,
1078 ruleptr, cur, test, report);
1079 if (testptr == NULL)
1080 xmlFree(test);
1081 }
1082 } else {
1083 xmlSchematronPErr(ctxt, cur,
1085 "Expecting an assert or a report element instead of %s",
1086 cur->name, NULL);
1087 }
1088 cur = cur->next;
1089 NEXT_SCHEMATRON(cur);
1090 }
1091 if (nbChecks == 0) {
1092 xmlSchematronPErr(ctxt, rule,
1094 "rule has no assert nor report element", NULL, NULL);
1095 }
1096}
1097
1105static void
1106xmlSchematronParsePattern(xmlSchematronParserCtxtPtr ctxt, xmlNodePtr pat)
1107{
1109 xmlSchematronPatternPtr pattern;
1110 int nbRules = 0;
1111 xmlChar *id;
1112
1113 if ((ctxt == NULL) || (pat == NULL)) return;
1114
1115 id = xmlGetNoNsProp(pat, BAD_CAST "id");
1116 if (id == NULL) {
1117 id = xmlGetNoNsProp(pat, BAD_CAST "name");
1118 }
1119 pattern = xmlSchematronAddPattern(ctxt, ctxt->schema, pat, id);
1120 if (pattern == NULL) {
1121 if (id != NULL)
1122 xmlFree(id);
1123 return;
1124 }
1125 cur = pat->children;
1126 NEXT_SCHEMATRON(cur);
1127 while (cur != NULL) {
1128 if (IS_SCHEMATRON(cur, "rule")) {
1129 xmlSchematronParseRule(ctxt, pattern, cur);
1130 nbRules++;
1131 } else {
1132 xmlSchematronPErr(ctxt, cur,
1134 "Expecting a rule element instead of %s", cur->name, NULL);
1135 }
1136 cur = cur->next;
1137 NEXT_SCHEMATRON(cur);
1138 }
1139 if (nbRules == 0) {
1140 xmlSchematronPErr(ctxt, pat,
1142 "Pattern has no rule element", NULL, NULL);
1143 }
1144}
1145
1146#if 0
1156static xmlNodePtr
1157xmlSchematronLoadInclude(xmlSchematronParserCtxtPtr ctxt, xmlNodePtr cur)
1158{
1160 xmlDocPtr doc = NULL;
1161 xmlChar *href = NULL;
1162 xmlChar *base = NULL;
1163 xmlChar *URI = NULL;
1164
1165 if ((ctxt == NULL) || (cur == NULL))
1166 return(NULL);
1167
1168 href = xmlGetNoNsProp(cur, BAD_CAST "href");
1169 if (href == NULL) {
1170 xmlSchematronPErr(ctxt, cur,
1172 "Include has no href attribute", NULL, NULL);
1173 return(cur->next);
1174 }
1175
1176 /* do the URI base composition, load and find the root */
1177 base = xmlNodeGetBase(cur->doc, cur);
1178 URI = xmlBuildURI(href, base);
1179 doc = xmlReadFile((const char *) URI, NULL, SCHEMATRON_PARSE_OPTIONS);
1180 if (doc == NULL) {
1181 xmlSchematronPErr(ctxt, cur,
1183 "could not load include '%s'.\n",
1184 URI, NULL);
1185 goto done;
1186 }
1188 if (ret == NULL) {
1189 xmlSchematronPErr(ctxt, cur,
1191 "could not find root from include '%s'.\n",
1192 URI, NULL);
1193 goto done;
1194 }
1195
1196 /* Success, push the include for rollback on exit */
1197 xmlSchematronPushInclude(ctxt, doc, cur);
1198
1199done:
1200 if (ret == NULL) {
1201 if (doc != NULL)
1202 xmlFreeDoc(doc);
1203 }
1204 xmlFree(href);
1205 if (base != NULL)
1206 xmlFree(base);
1207 if (URI != NULL)
1208 xmlFree(URI);
1209 return(ret);
1210}
1211#endif
1212
1223xmlSchematronPtr
1224xmlSchematronParse(xmlSchematronParserCtxtPtr ctxt)
1225{
1226 xmlSchematronPtr ret = NULL;
1227 xmlDocPtr doc;
1229 int preserve = 0;
1230
1231 if (ctxt == NULL)
1232 return (NULL);
1233
1234 ctxt->nberrors = 0;
1235
1236 /*
1237 * First step is to parse the input document into an DOM/Infoset
1238 */
1239 if (ctxt->URL != NULL) {
1240 doc = xmlReadFile((const char *) ctxt->URL, NULL,
1241 SCHEMATRON_PARSE_OPTIONS);
1242 if (doc == NULL) {
1243 xmlSchematronPErr(ctxt, NULL,
1245 "xmlSchematronParse: could not load '%s'.\n",
1246 ctxt->URL, NULL);
1247 return (NULL);
1248 }
1249 ctxt->preserve = 0;
1250 } else if (ctxt->buffer != NULL) {
1251 doc = xmlReadMemory(ctxt->buffer, ctxt->size, NULL, NULL,
1252 SCHEMATRON_PARSE_OPTIONS);
1253 if (doc == NULL) {
1254 xmlSchematronPErr(ctxt, NULL,
1256 "xmlSchematronParse: could not parse.\n",
1257 NULL, NULL);
1258 return (NULL);
1259 }
1260 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
1261 ctxt->URL = xmlDictLookup(ctxt->dict, BAD_CAST "in_memory_buffer", -1);
1262 ctxt->preserve = 0;
1263 } else if (ctxt->doc != NULL) {
1264 doc = ctxt->doc;
1265 preserve = 1;
1266 ctxt->preserve = 1;
1267 } else {
1268 xmlSchematronPErr(ctxt, NULL,
1270 "xmlSchematronParse: could not parse.\n",
1271 NULL, NULL);
1272 return (NULL);
1273 }
1274
1275 /*
1276 * Then extract the root and Schematron parse it
1277 */
1279 if (root == NULL) {
1280 xmlSchematronPErr(ctxt, (xmlNodePtr) doc,
1282 "The schema has no document element.\n", NULL, NULL);
1283 if (!preserve) {
1284 xmlFreeDoc(doc);
1285 }
1286 return (NULL);
1287 }
1288
1289 if (!IS_SCHEMATRON(root, "schema")) {
1290 xmlSchematronPErr(ctxt, root,
1292 "The XML document '%s' is not a XML schematron document",
1293 ctxt->URL, NULL);
1294 goto exit;
1295 }
1296 ret = xmlSchematronNewSchematron(ctxt);
1297 if (ret == NULL)
1298 goto exit;
1299 ctxt->schema = ret;
1300
1301 /*
1302 * scan the schema elements
1303 */
1304 cur = root->children;
1305 NEXT_SCHEMATRON(cur);
1306 if (IS_SCHEMATRON(cur, "title")) {
1308 if (title != NULL) {
1309 ret->title = xmlDictLookup(ret->dict, title, -1);
1310 xmlFree(title);
1311 }
1312 cur = cur->next;
1313 NEXT_SCHEMATRON(cur);
1314 }
1315 while (IS_SCHEMATRON(cur, "ns")) {
1316 xmlChar *prefix = xmlGetNoNsProp(cur, BAD_CAST "prefix");
1318 if ((uri == NULL) || (uri[0] == 0)) {
1319 xmlSchematronPErr(ctxt, cur,
1321 "ns element has no uri", NULL, NULL);
1322 }
1323 if ((prefix == NULL) || (prefix[0] == 0)) {
1324 xmlSchematronPErr(ctxt, cur,
1326 "ns element has no prefix", NULL, NULL);
1327 }
1328 if ((prefix) && (uri)) {
1329 xmlXPathRegisterNs(ctxt->xctxt, prefix, uri);
1330 xmlSchematronAddNamespace(ctxt, prefix, uri);
1331 ret->nbNs++;
1332 }
1333 if (uri)
1334 xmlFree(uri);
1335 if (prefix)
1336 xmlFree(prefix);
1337 cur = cur->next;
1338 NEXT_SCHEMATRON(cur);
1339 }
1340 while (cur != NULL) {
1341 if (IS_SCHEMATRON(cur, "pattern")) {
1342 xmlSchematronParsePattern(ctxt, cur);
1343 ret->nbPattern++;
1344 } else {
1345 xmlSchematronPErr(ctxt, cur,
1347 "Expecting a pattern element instead of %s", cur->name, NULL);
1348 }
1349 cur = cur->next;
1350 NEXT_SCHEMATRON(cur);
1351 }
1352 if (ret->nbPattern == 0) {
1353 xmlSchematronPErr(ctxt, root,
1355 "The schematron document '%s' has no pattern",
1356 ctxt->URL, NULL);
1357 goto exit;
1358 }
1359 /* the original document must be kept for reporting */
1360 ret->doc = doc;
1361 if (preserve) {
1362 ret->preserve = 1;
1363 }
1364 preserve = 1;
1365
1366exit:
1367 if (!preserve) {
1368 xmlFreeDoc(doc);
1369 }
1370 if (ret != NULL) {
1371 if (ctxt->nberrors != 0) {
1372 xmlSchematronFree(ret);
1373 ret = NULL;
1374 } else {
1375 ret->namespaces = ctxt->namespaces;
1376 ret->nbNamespaces = ctxt->nbNamespaces;
1377 ctxt->namespaces = NULL;
1378 }
1379 }
1380 return (ret);
1381}
1382
1383/************************************************************************
1384 * *
1385 * Schematrontron Reports handler *
1386 * *
1387 ************************************************************************/
1388
1389static xmlNodePtr
1390xmlSchematronGetNode(xmlSchematronValidCtxtPtr ctxt,
1391 xmlNodePtr cur, const xmlChar *xpath) {
1393 xmlXPathObjectPtr ret;
1394
1395 if ((ctxt == NULL) || (cur == NULL) || (xpath == NULL))
1396 return(NULL);
1397
1398 ctxt->xctxt->doc = cur->doc;
1399 ctxt->xctxt->node = cur;
1400 ret = xmlXPathEval(xpath, ctxt->xctxt);
1401 if (ret == NULL)
1402 return(NULL);
1403
1404 if ((ret->type == XPATH_NODESET) &&
1405 (ret->nodesetval != NULL) && (ret->nodesetval->nodeNr > 0))
1406 node = ret->nodesetval->nodeTab[0];
1407
1408 xmlXPathFreeObject(ret);
1409 return(node);
1410}
1411
1420static void
1421xmlSchematronReportOutput(xmlSchematronValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
1423 const char *msg) {
1424 /* TODO */
1425 fprintf(stderr, "%s", msg);
1426}
1427
1439static xmlChar *
1440xmlSchematronFormatReport(xmlSchematronValidCtxtPtr ctxt,
1442 xmlChar *ret = NULL;
1444 xmlXPathCompExprPtr comp;
1445
1446 if ((test == NULL) || (cur == NULL))
1447 return(ret);
1448
1449 child = test->children;
1450 while (child != NULL) {
1451 if ((child->type == XML_TEXT_NODE) ||
1452 (child->type == XML_CDATA_SECTION_NODE))
1453 ret = xmlStrcat(ret, child->content);
1454 else if (IS_SCHEMATRON(child, "name")) {
1455 xmlChar *path;
1456
1457 path = xmlGetNoNsProp(child, BAD_CAST "path");
1458
1459 node = cur;
1460 if (path != NULL) {
1461 node = xmlSchematronGetNode(ctxt, cur, path);
1462 if (node == NULL)
1463 node = cur;
1464 xmlFree(path);
1465 }
1466
1467 if ((node->ns == NULL) || (node->ns->prefix == NULL))
1468 ret = xmlStrcat(ret, node->name);
1469 else {
1470 ret = xmlStrcat(ret, node->ns->prefix);
1471 ret = xmlStrcat(ret, BAD_CAST ":");
1472 ret = xmlStrcat(ret, node->name);
1473 }
1474 } else if (IS_SCHEMATRON(child, "value-of")) {
1475 xmlChar *select;
1476 xmlXPathObjectPtr eval;
1477
1478 select = xmlGetNoNsProp(child, BAD_CAST "select");
1479 comp = xmlXPathCtxtCompile(ctxt->xctxt, select);
1480 eval = xmlXPathCompiledEval(comp, ctxt->xctxt);
1481
1482 switch (eval->type) {
1483 case XPATH_NODESET: {
1484 int indx;
1485 xmlChar *spacer = BAD_CAST " ";
1486
1487 if (eval->nodesetval) {
1488 for (indx = 0; indx < eval->nodesetval->nodeNr; indx++) {
1489 if (indx > 0)
1490 ret = xmlStrcat(ret, spacer);
1491 ret = xmlStrcat(ret, eval->nodesetval->nodeTab[indx]->name);
1492 }
1493 } else {
1495 "Empty node set\n");
1496 }
1497 break;
1498 }
1499 case XPATH_BOOLEAN: {
1500 const char *str = eval->boolval ? "True" : "False";
1502 break;
1503 }
1504 case XPATH_NUMBER: {
1505 xmlChar *buf;
1506 int size;
1507
1508 size = snprintf(NULL, 0, "%0g", eval->floatval);
1509 buf = (xmlChar*) malloc(size * sizeof(xmlChar));
1510 /* xmlStrPrintf(buf, size, "%0g", eval->floatval); // doesn't work */
1511 sprintf((char*) buf, "%0g", eval->floatval);
1512 ret = xmlStrcat(ret, buf);
1513 free(buf);
1514 break;
1515 }
1516 case XPATH_STRING:
1517 ret = xmlStrcat(ret, eval->stringval);
1518 break;
1519 default:
1521 "Unsupported XPATH Type: %d\n", eval->type);
1522 }
1523 xmlXPathFreeObject(eval);
1524 xmlXPathFreeCompExpr(comp);
1525 xmlFree(select);
1526 } else {
1527 child = child->next;
1528 continue;
1529 }
1530
1531 /*
1532 * remove superfluous \n
1533 */
1534 if (ret != NULL) {
1535 int len = xmlStrlen(ret);
1536 xmlChar c;
1537
1538 if (len > 0) {
1539 c = ret[len - 1];
1540 if ((c == ' ') || (c == '\n') || (c == '\r') || (c == '\t')) {
1541 while ((c == ' ') || (c == '\n') ||
1542 (c == '\r') || (c == '\t')) {
1543 len--;
1544 if (len == 0)
1545 break;
1546 c = ret[len - 1];
1547 }
1548 ret[len] = ' ';
1549 ret[len + 1] = 0;
1550 }
1551 }
1552 }
1553
1554 child = child->next;
1555 }
1556 return(ret);
1557}
1558
1569static void
1570xmlSchematronReportSuccess(xmlSchematronValidCtxtPtr ctxt,
1571 xmlSchematronTestPtr test, xmlNodePtr cur, xmlSchematronPatternPtr pattern, int success) {
1572 if ((ctxt == NULL) || (cur == NULL) || (test == NULL))
1573 return;
1574 /* if quiet and not SVRL report only failures */
1575 if ((ctxt->flags & XML_SCHEMATRON_OUT_QUIET) &&
1576 ((ctxt->flags & XML_SCHEMATRON_OUT_XML) == 0) &&
1577 (test->type == XML_SCHEMATRON_REPORT))
1578 return;
1579 if (ctxt->flags & XML_SCHEMATRON_OUT_XML) {
1580 TODO
1581 } else {
1582 xmlChar *path;
1583 char msg[1000];
1584 long line;
1585 const xmlChar *report = NULL;
1586
1587 if (((test->type == XML_SCHEMATRON_REPORT) & (!success)) ||
1588 ((test->type == XML_SCHEMATRON_ASSERT) & (success)))
1589 return;
1591 path = xmlGetNodePath(cur);
1592 if (path == NULL)
1593 path = (xmlChar *) cur->name;
1594#if 0
1595 if ((test->report != NULL) && (test->report[0] != 0))
1596 report = test->report;
1597#endif
1598 if (test->node != NULL)
1599 report = xmlSchematronFormatReport(ctxt, test->node, cur);
1600 if (report == NULL) {
1601 if (test->type == XML_SCHEMATRON_ASSERT) {
1602 report = xmlStrdup((const xmlChar *) "node failed assert");
1603 } else {
1604 report = xmlStrdup((const xmlChar *) "node failed report");
1605 }
1606 }
1607 snprintf(msg, 999, "%s line %ld: %s\n", (const char *) path,
1608 line, (const char *) report);
1609
1610 if (ctxt->flags & XML_SCHEMATRON_OUT_ERROR) {
1611 xmlStructuredErrorFunc schannel = NULL;
1612 xmlGenericErrorFunc channel = NULL;
1613 void *data = NULL;
1614
1615 if (ctxt != NULL) {
1616 if (ctxt->serror != NULL)
1617 schannel = ctxt->serror;
1618 else
1619 channel = ctxt->error;
1620 data = ctxt->userData;
1621 }
1622
1623 __xmlRaiseError(schannel, channel, data,
1625 (test->type == XML_SCHEMATRON_ASSERT)?XML_SCHEMATRONV_ASSERT:XML_SCHEMATRONV_REPORT,
1627 (pattern == NULL)?NULL:((const char *) pattern->name),
1628 (const char *) path,
1629 (const char *) report, 0, 0,
1630 "%s", msg);
1631 } else {
1632 xmlSchematronReportOutput(ctxt, cur, &msg[0]);
1633 }
1634
1635 xmlFree((char *) report);
1636
1637 if ((path != NULL) && (path != (xmlChar *) cur->name))
1638 xmlFree(path);
1639 }
1640}
1641
1649static void
1650xmlSchematronReportPattern(xmlSchematronValidCtxtPtr ctxt,
1651 xmlSchematronPatternPtr pattern) {
1652 if ((ctxt == NULL) || (pattern == NULL))
1653 return;
1654 if ((ctxt->flags & XML_SCHEMATRON_OUT_QUIET) || (ctxt->flags & XML_SCHEMATRON_OUT_ERROR)) /* Error gives pattern name as part of error */
1655 return;
1656 if (ctxt->flags & XML_SCHEMATRON_OUT_XML) {
1657 TODO
1658 } else {
1659 char msg[1000];
1660
1661 if (pattern->name == NULL)
1662 return;
1663 snprintf(msg, 999, "Pattern: %s\n", (const char *) pattern->name);
1664 xmlSchematronReportOutput(ctxt, NULL, &msg[0]);
1665 }
1666}
1667
1668
1669/************************************************************************
1670 * *
1671 * Validation against a Schematrontron *
1672 * *
1673 ************************************************************************/
1674
1683void
1684xmlSchematronSetValidStructuredErrors(xmlSchematronValidCtxtPtr ctxt,
1685 xmlStructuredErrorFunc serror, void *ctx)
1686{
1687 if (ctxt == NULL)
1688 return;
1689 ctxt->serror = serror;
1690 ctxt->error = NULL;
1691 ctxt->warning = NULL;
1692 ctxt->userData = ctx;
1693}
1694
1704xmlSchematronValidCtxtPtr
1705xmlSchematronNewValidCtxt(xmlSchematronPtr schema, int options)
1706{
1707 int i;
1708 xmlSchematronValidCtxtPtr ret;
1709
1710 ret = (xmlSchematronValidCtxtPtr) xmlMalloc(sizeof(xmlSchematronValidCtxt));
1711 if (ret == NULL) {
1712 xmlSchematronVErrMemory(NULL, "allocating validation context",
1713 NULL);
1714 return (NULL);
1715 }
1716 memset(ret, 0, sizeof(xmlSchematronValidCtxt));
1717 ret->type = XML_STRON_CTXT_VALIDATOR;
1718 ret->schema = schema;
1719 ret->xctxt = xmlXPathNewContext(NULL);
1720 ret->flags = options;
1721 if (ret->xctxt == NULL) {
1722 xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context",
1723 NULL);
1724 xmlSchematronFreeValidCtxt(ret);
1725 return (NULL);
1726 }
1727 for (i = 0;i < schema->nbNamespaces;i++) {
1728 if ((schema->namespaces[2 * i] == NULL) ||
1729 (schema->namespaces[2 * i + 1] == NULL))
1730 break;
1731 xmlXPathRegisterNs(ret->xctxt, schema->namespaces[2 * i + 1],
1732 schema->namespaces[2 * i]);
1733 }
1734 return (ret);
1735}
1736
1743void
1744xmlSchematronFreeValidCtxt(xmlSchematronValidCtxtPtr ctxt)
1745{
1746 if (ctxt == NULL)
1747 return;
1748 if (ctxt->xctxt != NULL)
1749 xmlXPathFreeContext(ctxt->xctxt);
1750 if (ctxt->dict != NULL)
1751 xmlDictFree(ctxt->dict);
1752 xmlFree(ctxt);
1753}
1754
1755static xmlNodePtr
1756xmlSchematronNextNode(xmlNodePtr cur) {
1757 if (cur->children != NULL) {
1758 /*
1759 * Do not descend on entities declarations
1760 */
1761 if (cur->children->type != XML_ENTITY_DECL) {
1762 cur = cur->children;
1763 /*
1764 * Skip DTDs
1765 */
1766 if (cur->type != XML_DTD_NODE)
1767 return(cur);
1768 }
1769 }
1770
1771 while (cur->next != NULL) {
1772 cur = cur->next;
1773 if ((cur->type != XML_ENTITY_DECL) &&
1774 (cur->type != XML_DTD_NODE))
1775 return(cur);
1776 }
1777
1778 do {
1779 cur = cur->parent;
1780 if (cur == NULL) break;
1781 if (cur->type == XML_DOCUMENT_NODE) return(NULL);
1782 if (cur->next != NULL) {
1783 cur = cur->next;
1784 return(cur);
1785 }
1786 } while (cur != NULL);
1787 return(cur);
1788}
1789
1801static int
1802xmlSchematronRunTest(xmlSchematronValidCtxtPtr ctxt,
1803 xmlSchematronTestPtr test, xmlDocPtr instance, xmlNodePtr cur, xmlSchematronPatternPtr pattern)
1804{
1805 xmlXPathObjectPtr ret;
1806 int failed;
1807
1808 failed = 0;
1809 ctxt->xctxt->doc = instance;
1810 ctxt->xctxt->node = cur;
1811 ret = xmlXPathCompiledEval(test->comp, ctxt->xctxt);
1812 if (ret == NULL) {
1813 failed = 1;
1814 } else {
1815 switch (ret->type) {
1816 case XPATH_XSLT_TREE:
1817 case XPATH_NODESET:
1818 if ((ret->nodesetval == NULL) ||
1819 (ret->nodesetval->nodeNr == 0))
1820 failed = 1;
1821 break;
1822 case XPATH_BOOLEAN:
1823 failed = !ret->boolval;
1824 break;
1825 case XPATH_NUMBER:
1826 if ((xmlXPathIsNaN(ret->floatval)) ||
1827 (ret->floatval == 0.0))
1828 failed = 1;
1829 break;
1830 case XPATH_STRING:
1831 if ((ret->stringval == NULL) ||
1832 (ret->stringval[0] == 0))
1833 failed = 1;
1834 break;
1835 case XPATH_UNDEFINED:
1836#ifdef LIBXML_XPTR_LOCS_ENABLED
1837 case XPATH_POINT:
1838 case XPATH_RANGE:
1839 case XPATH_LOCATIONSET:
1840#endif
1841 case XPATH_USERS:
1842 failed = 1;
1843 break;
1844 }
1845 xmlXPathFreeObject(ret);
1846 }
1847 if ((failed) && (test->type == XML_SCHEMATRON_ASSERT))
1848 ctxt->nberrors++;
1849 else if ((!failed) && (test->type == XML_SCHEMATRON_REPORT))
1850 ctxt->nberrors++;
1851
1852 xmlSchematronReportSuccess(ctxt, test, cur, pattern, !failed);
1853
1854 return(!failed);
1855}
1856
1868static int
1869xmlSchematronRegisterVariables(xmlXPathContextPtr ctxt, xmlSchematronLetPtr let,
1871{
1872 xmlXPathObjectPtr let_eval;
1873
1874 ctxt->doc = instance;
1875 ctxt->node = cur;
1876 while (let != NULL) {
1877 let_eval = xmlXPathCompiledEval(let->comp, ctxt);
1878 if (let_eval == NULL) {
1880 "Evaluation of compiled expression failed\n");
1881 return -1;
1882 }
1883 if(xmlXPathRegisterVariableNS(ctxt, let->name, NULL, let_eval)) {
1885 "Registering a let variable failed\n");
1886 return -1;
1887 }
1888 let = let->next;
1889 }
1890 return 0;
1891}
1892
1902static int
1903xmlSchematronUnregisterVariables(xmlXPathContextPtr ctxt, xmlSchematronLetPtr let)
1904{
1905 while (let != NULL) {
1906 if (xmlXPathRegisterVariableNS(ctxt, let->name, NULL, NULL)) {
1908 "Unregistering a let variable failed\n");
1909 return -1;
1910 }
1911 let = let->next;
1912 }
1913 return 0;
1914}
1915
1926int
1927xmlSchematronValidateDoc(xmlSchematronValidCtxtPtr ctxt, xmlDocPtr instance)
1928{
1930 xmlSchematronPatternPtr pattern;
1931 xmlSchematronRulePtr rule;
1932 xmlSchematronTestPtr test;
1933
1934 if ((ctxt == NULL) || (ctxt->schema == NULL) ||
1935 (ctxt->schema->rules == NULL) || (instance == NULL))
1936 return(-1);
1937 ctxt->nberrors = 0;
1939 if (root == NULL) {
1940 TODO
1941 ctxt->nberrors++;
1942 return(1);
1943 }
1944 if ((ctxt->flags & XML_SCHEMATRON_OUT_QUIET) ||
1945 (ctxt->flags == 0)) {
1946 /*
1947 * we are just trying to assert the validity of the document,
1948 * speed primes over the output, run in a single pass
1949 */
1950 cur = root;
1951 while (cur != NULL) {
1952 rule = ctxt->schema->rules;
1953 while (rule != NULL) {
1954 if (xmlPatternMatch(rule->pattern, cur) == 1) {
1955 test = rule->tests;
1956
1957 if (xmlSchematronRegisterVariables(ctxt->xctxt, rule->lets, instance, cur))
1958 return -1;
1959
1960 while (test != NULL) {
1961 xmlSchematronRunTest(ctxt, test, instance, cur, (xmlSchematronPatternPtr)rule->pattern);
1962 test = test->next;
1963 }
1964
1965 if (xmlSchematronUnregisterVariables(ctxt->xctxt, rule->lets))
1966 return -1;
1967
1968 }
1969 rule = rule->next;
1970 }
1971
1972 cur = xmlSchematronNextNode(cur);
1973 }
1974 } else {
1975 /*
1976 * Process all contexts one at a time
1977 */
1978 pattern = ctxt->schema->patterns;
1979
1980 while (pattern != NULL) {
1981 xmlSchematronReportPattern(ctxt, pattern);
1982
1983 /*
1984 * TODO convert the pattern rule to a direct XPath and
1985 * compute directly instead of using the pattern matching
1986 * over the full document...
1987 * Check the exact semantic
1988 */
1989 cur = root;
1990 while (cur != NULL) {
1991 rule = pattern->rules;
1992 while (rule != NULL) {
1993 if (xmlPatternMatch(rule->pattern, cur) == 1) {
1994 test = rule->tests;
1995 xmlSchematronRegisterVariables(ctxt->xctxt, rule->lets,
1996 instance, cur);
1997
1998 while (test != NULL) {
1999 xmlSchematronRunTest(ctxt, test, instance, cur, pattern);
2000 test = test->next;
2001 }
2002
2003 xmlSchematronUnregisterVariables(ctxt->xctxt, rule->lets);
2004 }
2005 rule = rule->patnext;
2006 }
2007
2008 cur = xmlSchematronNextNode(cur);
2009 }
2010 pattern = pattern->next;
2011 }
2012 }
2013 return(ctxt->nberrors);
2014}
2015
2016#ifdef STANDALONE
2017int
2018main(void)
2019{
2020 int ret;
2022 xmlSchematronParserCtxtPtr pctxt;
2023 xmlSchematronValidCtxtPtr vctxt;
2024 xmlSchematronPtr schema = NULL;
2025
2026 pctxt = xmlSchematronNewParserCtxt("tst.sct");
2027 if (pctxt == NULL) {
2028 fprintf(stderr, "failed to build schematron parser\n");
2029 } else {
2030 schema = xmlSchematronParse(pctxt);
2031 if (schema == NULL) {
2032 fprintf(stderr, "failed to compile schematron\n");
2033 }
2034 xmlSchematronFreeParserCtxt(pctxt);
2035 }
2036 instance = xmlReadFile("tst.sct", NULL,
2038 if (instance == NULL) {
2039 fprintf(stderr, "failed to parse instance\n");
2040 }
2041 if ((schema != NULL) && (instance != NULL)) {
2042 vctxt = xmlSchematronNewValidCtxt(schema);
2043 if (vctxt == NULL) {
2044 fprintf(stderr, "failed to build schematron validator\n");
2045 } else {
2046 ret = xmlSchematronValidateDoc(vctxt, instance);
2047 xmlSchematronFreeValidCtxt(vctxt);
2048 }
2049 }
2050 xmlSchematronFree(schema);
2052
2054 xmlMemoryDump();
2055
2056 return (0);
2057}
2058#endif
2059
2060#endif /* LIBXML_SCHEMATRON_ENABLED */
#define TODO
Definition: SAX2.c:44
#define msg(x)
Definition: auth_time.c:54
struct _root root
static struct loaded_include * includes
Definition: compiler.c:53
#define free
Definition: debug_ros.c:5
#define malloc
Definition: debug_ros.c:4
#define NULL
Definition: types.h:112
static HINSTANCE instance
Definition: main.c:40
static void report(const DATA_BLOB *pDataIn, const DATA_BLOB *pOptionalEntropy, CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct, DWORD dwFlags)
Definition: protectdata.c:769
INT WSAAPI select(IN INT s, IN OUT LPFD_SET readfds, IN OUT LPFD_SET writefds, IN OUT LPFD_SET exceptfds, IN CONST struct timeval *timeout)
Definition: select.c:41
int main()
Definition: test.c:6
FxCollectionEntry * cur
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLsizeiptr size
Definition: glext.h:5919
GLuint buffer
Definition: glext.h:5915
const GLubyte * c
Definition: glext.h:8905
GLubyte * pattern
Definition: glext.h:7787
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLbitfield flags
Definition: glext.h:7161
GLuint GLsizei const GLvoid GLenum preserve
Definition: glext.h:9550
GLenum GLsizei len
Definition: glext.h:6722
GLuint id
Definition: glext.h:5910
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define ATTRIBUTE_UNUSED
Definition: i386-dis.c:36
@ extra
Definition: id3.c:95
#define stderr
Definition: stdio.h:100
_Check_return_opt_ _CRTIMP int __cdecl fprintf(_Inout_ FILE *_File, _In_z_ _Printf_format_string_ const char *_Format,...)
#define c
Definition: ke_i.h:80
if(dx< 0)
Definition: linetemp.h:194
const WCHAR * schema
#define error(str)
Definition: mkdosfs.c:1605
static struct test_info tests[]
#define sprintf(buf, format,...)
Definition: sprintf.c:55
const char * uri
Definition: sec_mgr.c:1588
static HWND child
Definition: cursoricon.c:298
static char title[]
Definition: ps.c:92
static unsigned __int64 next
Definition: rand_nt.c:6
#define err(...)
#define test
Definition: rosglue.h:37
const WCHAR * str
#define warning(s)
Definition: debug.h:83
XMLPUBFUN const xmlChar *XMLCALL xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len)
Definition: dict.c:867
XMLPUBFUN xmlDictPtr XMLCALL xmlDictCreate(void)
Definition: dict.c:577
XMLPUBFUN void XMLCALL xmlDictFree(xmlDictPtr dict)
Definition: dict.c:802
XMLPUBFUN int XMLCALL xmlDictReference(xmlDictPtr dict)
Definition: dict.c:647
XMLPUBVAR xmlMallocFunc xmlMalloc
Definition: globals.h:248
XMLPUBVAR xmlFreeFunc xmlFree
Definition: globals.h:251
XMLPUBVAR void * xmlGenericErrorContext
Definition: globals.h:353
XMLPUBVAR xmlReallocFunc xmlRealloc
Definition: globals.h:250
XMLPUBVAR xmlGenericErrorFunc xmlGenericError
Definition: globals.h:337
XMLPUBFUN xmlDocPtr XMLCALL xmlReadMemory(const char *buffer, int size, const char *URL, const char *encoding, int options)
Definition: parser.c:15253
XMLPUBFUN xmlDocPtr XMLCALL xmlReadFile(const char *URL, const char *encoding, int options)
Definition: parser.c:15229
XMLPUBFUN void XMLCALL xmlCleanupParser(void)
Definition: parser.c:14739
@ XML_PARSE_NOCDATA
Definition: parser.h:1107
@ XML_PARSE_NOENT
Definition: parser.h:1094
XMLPUBFUN xmlChar *XMLCALL xmlNodeGetContent(const xmlNode *cur)
XMLPUBFUN xmlNodePtr XMLCALL xmlDocGetRootElement(const xmlDoc *doc)
XMLPUBFUN void XMLCALL xmlFreeDoc(xmlDocPtr cur)
XMLPUBFUN xmlChar *XMLCALL xmlGetNoNsProp(const xmlNode *node, const xmlChar *name)
xmlNode * xmlNodePtr
Definition: tree.h:488
xmlDoc * xmlDocPtr
Definition: tree.h:550
@ XML_ENTITY_DECL
Definition: tree.h:176
@ XML_DOCUMENT_NODE
Definition: tree.h:168
@ XML_CDATA_SECTION_NODE
Definition: tree.h:163
@ XML_TEXT_NODE
Definition: tree.h:162
@ XML_DTD_NODE
Definition: tree.h:173
XMLPUBFUN xmlChar *XMLCALL xmlNodeGetBase(const xmlDoc *doc, const xmlNode *cur)
XMLPUBFUN long XMLCALL xmlGetLineNo(const xmlNode *node)
#define exit(n)
Definition: config.h:202
#define memset(x, y, z)
Definition: compat.h:39
Definition: dict.c:111
Definition: tree.h:551
const xmlChar * URL
Definition: tree.h:577
struct _xmlDoc * doc
Definition: tree.h:560
Definition: tree.h:489
struct _xmlNode * children
Definition: tree.h:493
Definition: http.c:7252
struct define * next
Definition: compiler.c:65
char * name
Definition: compiler.c:66
Definition: parser.c:49
Definition: name.c:39
Definition: mxnamespace.c:45
Definition: dlist.c:348
Definition: pdh_main.c:94
XMLPUBFUN xmlChar *XMLCALL xmlBuildURI(const xmlChar *URI, const xmlChar *base)
Definition: uri.c:1892
int ret
#define success(from, fromstr, to, tostr)
#define snprintf
Definition: wintirpc.h:48
void(XMLCDECL * xmlGenericErrorFunc)(void *ctx, const char *msg,...) LIBXML_ATTR_FORMAT(2
Definition: xmlerror.h:847
@ XML_ERR_ERROR
Definition: xmlerror.h:27
@ XML_FROM_SCHEMASP
Definition: xmlerror.h:53
@ XML_FROM_SCHEMASV
Definition: xmlerror.h:54
@ XML_FROM_SCHEMATRONV
Definition: xmlerror.h:65
void(XMLCDECL *) typedef void(XMLCALL * xmlStructuredErrorFunc)(void *userData, xmlErrorPtr error)
Definition: xmlerror.h:858
@ XML_SCHEMAP_FAILED_PARSE
Definition: xmlerror.h:565
@ XML_SCHEMAP_FAILED_LOAD
Definition: xmlerror.h:556
@ XML_SCHEMATRONV_REPORT
Definition: xmlerror.h:789
@ XML_SCHEMAP_NOTHING_TO_PARSE
Definition: xmlerror.h:557
@ XML_SCHEMAV_ATTRINVALID
Definition: xmlerror.h:620
@ XML_SCHEMAV_INTERNAL
Definition: xmlerror.h:617
@ XML_SCHEMATRONV_ASSERT
Definition: xmlerror.h:788
@ XML_SCHEMAP_NOROOT
Definition: xmlerror.h:558
@ XML_ERR_NO_MEMORY
Definition: xmlerror.h:102
XMLPUBFUN void XMLCALL xmlMemoryDump(void)
Definition: xmlmemory.c:910
XMLPUBFUN xmlChar *XMLCALL xmlStrcat(xmlChar *cur, const xmlChar *add)
Definition: xmlstring.c:524
XMLPUBFUN xmlChar *XMLCALL xmlStrdup(const xmlChar *cur)
Definition: xmlstring.c:67
#define BAD_CAST
Definition: xmlstring.h:35
XMLPUBFUN int XMLCALL xmlStrlen(const xmlChar *str)
Definition: xmlstring.c:426
unsigned char xmlChar
Definition: xmlstring.h:28
#define LIBXML_ATTR_FORMAT(fmt, args)
Definition: xmlversion.h:486
#define const
Definition: zconf.h:233