started adding schematron to the xmllint tool, the report infrastructure
* schematron.c xmllint.c: started adding schematron to the xmllint
tool, the report infrastructure is gonna be fun.
Daniel
diff --git a/ChangeLog b/ChangeLog
index 5740b22..20bd0e3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Sun Jul 24 10:25:41 EDT 2005 Daniel Veillard <daniel@veillard.com>
+
+ * schematron.c xmllint.c: started adding schematron to the xmllint
+ tool, the report infrastructure is gonna be fun.
+
Sat Jul 23 23:23:51 CEST 2005 Kasimier Buchcik <libxml2-cvs@cazic.net>
* test/schemas/any6* test/schemas/any7*: Added regression tests
diff --git a/schematron.c b/schematron.c
index 4211b78..dbf4543 100644
--- a/schematron.c
+++ b/schematron.c
@@ -63,6 +63,7 @@
xmlNodePtr node; /* the node in the tree */
xmlChar *test; /* the expression to test */
xmlXPathCompExprPtr comp; /* the compiled expression */
+ xmlChar *report; /* the message to report */
};
/**
@@ -78,6 +79,7 @@
xmlChar *context; /* the context evaluation rule */
xmlSchematronTestPtr tests; /* the list of tests */
xmlPatternPtr pattern; /* the compiled pattern associated */
+ xmlChar *report; /* the message to report */
};
/**
@@ -247,6 +249,7 @@
* @schema: a schema structure
* @node: the node hosting the test
* @context: the associated context string
+ * @report: the associated report string
*
* Add a test to a schematron
*
@@ -255,7 +258,7 @@
static xmlSchematronTestPtr
xmlSchematronAddTest(xmlSchematronParserCtxtPtr ctxt, int type,
xmlSchematronRulePtr rule,
- xmlNodePtr node, xmlChar *test)
+ xmlNodePtr node, xmlChar *test, xmlChar *report)
{
xmlSchematronTestPtr ret;
xmlXPathCompExprPtr comp;
@@ -286,6 +289,7 @@
ret->node = node;
ret->test = test;
ret->comp = comp;
+ ret->report = report;
ret->next = rule->tests;
rule->tests = ret;
return (ret);
@@ -307,6 +311,8 @@
xmlFree(tests->test);
if (tests->comp != NULL)
xmlXPathFreeCompExpr(tests->comp);
+ if (tests->report != NULL)
+ xmlFree(tests->report);
xmlFree(tests);
tests = next;
}
@@ -318,6 +324,7 @@
* @schema: a schema structure
* @node: the node hosting the rule
* @context: the associated context string
+ * @report: the associated report string
*
* Add a rule to a schematron
*
@@ -325,7 +332,7 @@
*/
static xmlSchematronRulePtr
xmlSchematronAddRule(xmlSchematronParserCtxtPtr ctxt, xmlSchematronPtr schema,
- xmlNodePtr node, xmlChar *context)
+ xmlNodePtr node, xmlChar *context, xmlChar *report)
{
xmlSchematronRulePtr ret;
xmlPatternPtr pattern;
@@ -356,6 +363,7 @@
ret->context = context;
ret->next = schema->rules;
ret->pattern = pattern;
+ ret->report = report;
schema->rules = ret;
return (ret);
}
@@ -378,6 +386,8 @@
xmlFree(rules->context);
if (rules->pattern)
xmlFreePattern(rules->pattern);
+ if (rules->report != NULL)
+ xmlFree(rules->report);
xmlFree(rules);
rules = next;
}
@@ -704,6 +714,7 @@
int nbChecks = 0;
xmlChar *test;
xmlChar *context;
+ xmlChar *report;
xmlSchematronRulePtr ruleptr;
xmlSchematronTestPtr testptr;
@@ -724,7 +735,7 @@
xmlFree(context);
return;
} else {
- ruleptr = xmlSchematronAddRule(ctxt, ctxt->schema, rule, context);
+ ruleptr = xmlSchematronAddRule(ctxt, ctxt->schema, rule, context, NULL);
if (ruleptr == NULL) {
xmlFree(context);
return;
@@ -749,8 +760,11 @@
NULL, NULL);
xmlFree(test);
} else {
+ /* TODO will need dynamic processing instead */
+ report = xmlNodeGetContent(cur);
+
testptr = xmlSchematronAddTest(ctxt, XML_SCHEMATRON_ASSERT,
- ruleptr, cur, test);
+ ruleptr, cur, test, report);
if (testptr == NULL)
xmlFree(test);
}
@@ -769,8 +783,11 @@
NULL, NULL);
xmlFree(test);
} else {
+ /* TODO will need dynamic processing instead */
+ report = xmlNodeGetContent(cur);
+
testptr = xmlSchematronAddTest(ctxt, XML_SCHEMATRON_REPORT,
- ruleptr, cur, test);
+ ruleptr, cur, test, report);
if (testptr == NULL)
xmlFree(test);
}
@@ -1057,9 +1074,68 @@
* *
************************************************************************/
+/**
+ * xmlSchematronReportOutput:
+ * @ctxt: the validation context
+ * @cur: the current node tested
+ * @msg: the message output
+ *
+ * Output part of the report to whatever channel the user selected
+ */
+static void
+xmlSchematronReportOutput(xmlSchematronValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
+ xmlNodePtr cur ATTRIBUTE_UNUSED,
+ const char *msg ATTRIBUTE_UNUSED) {
+ /* TODO */
+ fprintf(stderr, "%s", msg);
+}
+
+/**
+ * xmlSchematronReportSuccess:
+ * @ctxt: the validation context
+ * @test: the compiled test
+ * @cur: the current node tested
+ * @success: boolean value for the result
+ *
+ * called from the validation engine when an assert or report test have
+ * been done.
+ */
static void
xmlSchematronReportSuccess(xmlSchematronValidCtxtPtr ctxt,
- xmlSchematronTestPtr test, xmlNodePtr cur) {
+ xmlSchematronTestPtr test, xmlNodePtr cur, int success) {
+ if ((ctxt == NULL) || (cur == NULL) || (test == NULL))
+ return;
+ /* if quiet and not SVRL report only failures */
+ if ((ctxt->flags & XML_SCHEMATRON_OUT_QUIET) &&
+ ((ctxt->flags & XML_SCHEMATRON_OUT_XML) == 0) && (success))
+ return;
+ if (ctxt->flags & XML_SCHEMATRON_OUT_XML) {
+ TODO
+ } else {
+ xmlChar *path;
+ char msg[1000];
+ long line;
+ const xmlChar *report;
+
+ if (success)
+ return;
+ line = xmlGetLineNo(cur);
+ path = xmlGetNodePath(cur);
+ if (path == NULL)
+ path = (xmlChar *) cur->name;
+ if ((test->report != NULL) && (test->report[0] != 0))
+ report = test->report;
+ else if (test->type == XML_SCHEMATRON_ASSERT) {
+ report = BAD_CAST "node failed assert";
+ } else {
+ report = BAD_CAST "node failed report";
+ }
+ snprintf(msg, 999, "%s line %ld:\n %s\n", (const char *) path,
+ line, (const char *) report);
+ xmlSchematronReportOutput(ctxt, cur, &msg[0]);
+ if ((path != NULL) && (path != (xmlChar *) cur->name))
+ xmlFree(path);
+ }
}
/************************************************************************
@@ -1095,6 +1171,7 @@
ret->type = XML_STRON_CTXT_VALIDATOR;
ret->schema = schema;
ret->xctxt = xmlXPathNewContext(NULL);
+ ret->flags = options;
if (ret->xctxt == NULL) {
xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context",
NULL);
@@ -1216,15 +1293,9 @@
failed = 1;
break;
}
- if (test->type == XML_SCHEMATRON_REPORT) {
- if (!failed) {
- printf("report failed\n");
- }
- } else {
- if (failed) {
- printf("assert failed\n");
- }
- }
+ if (failed)
+ ctxt->nberrors++;
+ xmlSchematronReportSuccess(ctxt, test, cur, !failed);
return(!failed);
}
@@ -1255,7 +1326,6 @@
rule = ctxt->schema->rules;
while (rule != NULL) {
if (xmlPatternMatch(rule->pattern, cur) == 1) {
- printf("%s matches\n", cur->name);
test = rule->tests;
while (test != NULL) {
xmlSchematronRunTest(ctxt, test, instance, cur);
diff --git a/xmllint.c b/xmllint.c
index a434bbb..f330539 100644
--- a/xmllint.c
+++ b/xmllint.c
@@ -85,6 +85,9 @@
#endif
#include <libxml/globals.h>
#include <libxml/xmlreader.h>
+#ifdef LIBXML_SCHEMATRON_ENABLED
+#include <libxml/schematron.h>
+#endif
#ifdef LIBXML_SCHEMAS_ENABLED
#include <libxml/relaxng.h>
#include <libxml/xmlschemas.h>
@@ -143,6 +146,10 @@
static char * schema = NULL;
static xmlSchemaPtr wxschemas = NULL;
#endif
+#ifdef LIBXML_SCHEMAS_ENABLED
+static char * schematron = NULL;
+static xmlSchematronPtr wxschematron = NULL;
+#endif
static int repeat = 0;
static int insert = 0;
#if defined(LIBXML_HTML_ENABLED) || defined(LIBXML_VALID_ENABLED)
@@ -2580,6 +2587,42 @@
xmlFreeValidCtxt(cvp);
}
#endif /* LIBXML_VALID_ENABLED */
+#ifdef LIBXML_SCHEMATRON_ENABLED
+ if (wxschematron != NULL) {
+ xmlSchematronValidCtxtPtr ctxt;
+ int ret;
+ int flag = XML_SCHEMATRON_OUT_TEXT;
+
+ if ((timing) && (!repeat)) {
+ startTimer();
+ }
+
+ if (debug)
+ flag = XML_SCHEMATRON_OUT_XML;
+ ctxt = xmlSchematronNewValidCtxt(wxschematron, flag);
+#if 0
+ xmlSchematronSetValidErrors(ctxt,
+ (xmlSchematronValidityErrorFunc) fprintf,
+ (xmlSchematronValidityWarningFunc) fprintf,
+ stderr);
+#endif
+ ret = xmlSchematronValidateDoc(ctxt, doc);
+ if (ret == 0) {
+ fprintf(stderr, "%s validates\n", filename);
+ } else if (ret > 0) {
+ fprintf(stderr, "%s fails to validate\n", filename);
+ progresult = XMLLINT_ERR_VALID;
+ } else {
+ fprintf(stderr, "%s validation generated an internal error\n",
+ filename);
+ progresult = XMLLINT_ERR_VALID;
+ }
+ xmlSchematronFreeValidCtxt(ctxt);
+ if ((timing) && (!repeat)) {
+ endTimer("Validating");
+ }
+ }
+#endif
#ifdef LIBXML_SCHEMAS_ENABLED
if (relaxngschemas != NULL) {
xmlRelaxNGValidCtxtPtr ctxt;
@@ -3112,6 +3155,13 @@
schema = argv[i];
noent++;
#endif
+#ifdef LIBXML_SCHEMATRON_ENABLED
+ } else if ((!strcmp(argv[i], "-schematron")) ||
+ (!strcmp(argv[i], "--schematron"))) {
+ i++;
+ schematron = argv[i];
+ noent++;
+#endif
} else if ((!strcmp(argv[i], "-nonet")) ||
(!strcmp(argv[i], "--nonet"))) {
options |= XML_PARSE_NONET;
@@ -3193,6 +3243,40 @@
argv[0]);
}
+#ifdef LIBXML_SCHEMATRON_ENABLED
+ if ((schematron != NULL) && (sax == 0)
+#ifdef LIBXML_READER_ENABLED
+ && (stream == 0)
+#endif /* LIBXML_READER_ENABLED */
+ ) {
+ xmlSchematronParserCtxtPtr ctxt;
+
+ /* forces loading the DTDs */
+ xmlLoadExtDtdDefaultValue |= 1;
+ options |= XML_PARSE_DTDLOAD;
+ if (timing) {
+ startTimer();
+ }
+ ctxt = xmlSchematronNewParserCtxt(schematron);
+#if 0
+ xmlSchematronSetParserErrors(ctxt,
+ (xmlSchematronValidityErrorFunc) fprintf,
+ (xmlSchematronValidityWarningFunc) fprintf,
+ stderr);
+#endif
+ wxschematron = xmlSchematronParse(ctxt);
+ if (wxschematron == NULL) {
+ xmlGenericError(xmlGenericErrorContext,
+ "Schematron schema %s failed to compile\n", schematron);
+ progresult = XMLLINT_ERR_SCHEMACOMP;
+ schematron = NULL;
+ }
+ xmlSchematronFreeParserCtxt(ctxt);
+ if (timing) {
+ endTimer("Compiling the schemas");
+ }
+ }
+#endif
#ifdef LIBXML_SCHEMAS_ENABLED
if ((relaxng != NULL) && (sax == 0)
#ifdef LIBXML_READER_ENABLED
@@ -3309,6 +3393,11 @@
i++;
continue;
}
+ if ((!strcmp(argv[i], "-schematron")) ||
+ (!strcmp(argv[i], "--schematron"))) {
+ i++;
+ continue;
+ }
#ifdef LIBXML_PATTERN_ENABLED
if ((!strcmp(argv[i], "-pattern")) ||
(!strcmp(argv[i], "--pattern"))) {
@@ -3375,6 +3464,10 @@
if ((files == 0) && (!generate) && (version == 0)) {
usage(argv[0]);
}
+#ifdef LIBXML_SCHEMATRON_ENABLED
+ if (wxschematron != NULL)
+ xmlSchematronFree(wxschematron);
+#endif
#ifdef LIBXML_SCHEMAS_ENABLED
if (relaxngschemas != NULL)
xmlRelaxNGFree(relaxngschemas);