Fix file and line report for XSD SAX and reader streaming validation
Things now work correctly at the xmllint level:
thinkpad:~/XML -> xmllint --sax --noout --schema test_schema.xsd
test_xml.xml
test_xml.xml:72721: Schemas validity error : Element 'level1': Missing
child element(s). Expected is ( level2 ).
test_xml.xml fails to validate
thinkpad:~/XML -> xmllint --stream --schema test_schema.xsd test_xml.xml
test_xml.xml:72721: Schemas validity error : Element 'level1': Missing
child element(s). Expected is ( level2 ).
test_xml.xml fails to validate
thinkpad:~/XML ->
* error.c: fix a corner case of not reporting lines when we should
* include/libxml/xmlschemas.h doc/symbols.xml: had to add new entry
points to set the filename on a validation context and a locator
callback used to fetch the line and file from the context
* xmlschemas.c: add the new entry points xmlSchemaValidateSetFilename()
and xmlSchemaValidateSetLocator(), plus make sure the error reporting
routine gets the information if available. Add a locator for SAX.
* xmlreader.c: add and plug a locator for readers.
diff --git a/doc/symbols.xml b/doc/symbols.xml
index ee16185..7f6d692 100644
--- a/doc/symbols.xml
+++ b/doc/symbols.xml
@@ -1754,6 +1754,8 @@
<symbol file="tree">xmlBufUse</symbol>
<symbol file="dict">xmlDictGetUsage</symbol>
<symbol file="dict">xmlDictSetLimit</symbol>
+ <symbol file="xmlschemas">xmlSchemaValidateSetFilename</symbol>
+ <symbol file="xmlschemas">xmlSchemaValidateSetLocator</symbol>
<symbol file="xmlIO">xmlOutputBufferGetContent</symbol>
<symbol file="xmlIO">xmlOutputBufferGetSize</symbol>
</release>
diff --git a/error.c b/error.c
index b5e4c28..1c2fb36 100644
--- a/error.c
+++ b/error.c
@@ -292,7 +292,10 @@
} else {
if (file != NULL)
channel(data, "%s:%d: ", file, line);
- else if ((line != 0) && (domain == XML_FROM_PARSER))
+ else if ((line != 0) &&
+ ((domain == XML_FROM_PARSER) || (domain == XML_FROM_SCHEMASV)||
+ (domain == XML_FROM_SCHEMASP)||(domain == XML_FROM_DTD) ||
+ (domain == XML_FROM_RELAXNGP)||(domain == XML_FROM_RELAXNGV)))
channel(data, "Entity: line %d: ", line);
}
if (name != NULL) {
diff --git a/include/libxml/xmlschemas.h b/include/libxml/xmlschemas.h
index 752bc3a..b070d5c 100644
--- a/include/libxml/xmlschemas.h
+++ b/include/libxml/xmlschemas.h
@@ -113,6 +113,22 @@
typedef struct _xmlSchemaValidCtxt xmlSchemaValidCtxt;
typedef xmlSchemaValidCtxt *xmlSchemaValidCtxtPtr;
+/**
+ * xmlSchemaValidityLocatorFunc:
+ * @ctx: user provided context
+ * @file: returned file information
+ * @line: returned line information
+ *
+ * A schemas validation locator, a callback called by the validator.
+ * This is used when file or node informations are not available
+ * to find out what file and line number are affected
+ *
+ * Returns: 0 in case of success and -1 in case of error
+ */
+
+typedef int (XMLCDECL *xmlSchemaValidityLocatorFunc) (void *ctx,
+ const char **file, unsigned long *line);
+
/*
* Interfaces for parsing.
*/
@@ -171,6 +187,9 @@
XMLPUBFUN int XMLCALL
xmlSchemaSetValidOptions (xmlSchemaValidCtxtPtr ctxt,
int options);
+XMLPUBFUN void XMLCALL
+ xmlSchemaValidateSetFilename(xmlSchemaValidCtxtPtr vctxt,
+ const char *filename);
XMLPUBFUN int XMLCALL
xmlSchemaValidCtxtGetOptions(xmlSchemaValidCtxtPtr ctxt);
@@ -210,6 +229,13 @@
void **user_data);
XMLPUBFUN int XMLCALL
xmlSchemaSAXUnplug (xmlSchemaSAXPlugPtr plug);
+
+
+XMLPUBFUN void XMLCALL
+ xmlSchemaValidateSetLocator (xmlSchemaValidCtxtPtr vctxt,
+ xmlSchemaValidityLocatorFunc f,
+ void *ctxt);
+
#ifdef __cplusplus
}
#endif
diff --git a/xmllint.c b/xmllint.c
index 78db222..b58d184 100644
--- a/xmllint.c
+++ b/xmllint.c
@@ -1669,6 +1669,7 @@
(xmlSchemaValidityErrorFunc) fprintf,
(xmlSchemaValidityWarningFunc) fprintf,
stderr);
+ xmlSchemaValidateSetFilename(vctxt, filename);
ret = xmlSchemaValidateStream(vctxt, buf, 0, handler,
(void *)user_data);
diff --git a/xmlreader.c b/xmlreader.c
index f9c7fa1..c6ca46e 100644
--- a/xmlreader.c
+++ b/xmlreader.c
@@ -4155,6 +4155,60 @@
}
/**
+ * xmlTextReaderLocator:
+ * @ctx: the xmlTextReaderPtr used
+ * @file: returned file information
+ * @line: returned line information
+ *
+ * Internal locator function for the readers
+ *
+ * Returns 0 in case the Schema validation could be (des)activated and
+ * -1 in case of error.
+ */
+static int
+xmlTextReaderLocator(void *ctx, const char **file, unsigned long *line) {
+ xmlTextReaderPtr reader;
+
+ if ((ctx == NULL) || ((file == NULL) && (line == NULL)))
+ return(-1);
+
+ if (file != NULL)
+ *file = NULL;
+ if (line != NULL)
+ *line = 0;
+
+ reader = (xmlTextReaderPtr) ctx;
+ if ((reader->ctxt != NULL) && (reader->ctxt->input != NULL)) {
+ if (file != NULL)
+ *file = reader->ctxt->input->filename;
+ if (line != NULL)
+ *line = reader->ctxt->input->line;
+ return(0);
+ }
+ if (reader->node != NULL) {
+ long res;
+ int ret = 0;
+
+ if (line != NULL) {
+ res = xmlGetLineNo(reader->node);
+ if (res > 0)
+ *line = (unsigned long) res;
+ else
+ ret = -1;
+ }
+ if (file != NULL) {
+ xmlDocPtr doc = reader->node->doc;
+ if ((doc != NULL) && (doc->URL != NULL))
+ *file = (const char *) doc->URL;
+ else
+ ret = -1;
+ }
+ return(ret);
+ }
+ return(-1);
+}
+
+/**
* xmlTextReaderSetSchema:
* @reader: the xmlTextReaderPtr used
* @schema: a precompiled Schema schema
@@ -4221,6 +4275,10 @@
reader->xsdValidCtxt = NULL;
return(-1);
}
+ xmlSchemaValidateSetLocator(reader->xsdValidCtxt,
+ xmlTextReaderLocator,
+ (void *) reader);
+
if (reader->errorFunc != NULL) {
xmlSchemaSetValidErrors(reader->xsdValidCtxt,
xmlTextReaderValidityErrorRelay,
@@ -4435,6 +4493,9 @@
return(-1);
}
}
+ xmlSchemaValidateSetLocator(reader->xsdValidCtxt,
+ xmlTextReaderLocator,
+ (void *) reader);
/*
* Redirect the validation context's error channels to use
* the reader channels.
diff --git a/xmlschemas.c b/xmlschemas.c
index 2fb2151..de07993 100644
--- a/xmlschemas.c
+++ b/xmlschemas.c
@@ -975,6 +975,7 @@
xmlSAXHandlerPtr sax;
xmlParserCtxtPtr parserCtxt;
void *user_data; /* TODO: What is this for? */
+ char *filename;
int err;
int nberrors;
@@ -1028,6 +1029,10 @@
int hasKeyrefs;
int createIDCNodeTables;
int psviExposeIDCNodeTables;
+
+ /* Locator for error reporting in streaming mode */
+ xmlSchemaValidityLocatorFunc locFunc;
+ void *locCtxt;
};
/**
@@ -2078,6 +2083,20 @@
(vctxt->parserCtxt->input != NULL))
file = vctxt->parserCtxt->input->filename;
}
+ if (vctxt->locFunc != NULL) {
+ if ((file == NULL) || (line == 0)) {
+ unsigned long l;
+ const char *f;
+ vctxt->locFunc(vctxt->locCtxt, &f, &l);
+ if (file == NULL)
+ file = f;
+ if (line == 0)
+ line = (int) l;
+ }
+ }
+ if ((file == NULL) && (vctxt->filename != NULL))
+ file = vctxt->filename;
+
__xmlRaiseError(schannel, channel, data, ctxt,
node, XML_FROM_SCHEMASV,
error, errorLevel, file, line,
@@ -27450,8 +27469,28 @@
}
/**
- * xmlSchemaClearValidCtxt:
+ * xmlSchemaValidateSetFilename:
* @ctxt: the schema validation context
+ * @filename: the file name
+ *
+ * Workaround to provide file error reporting information when this is
+ * not provided by current APIs
+ */
+void
+xmlSchemaValidateSetFilename(xmlSchemaValidCtxtPtr vctxt, const char *filename) {
+ if (vctxt == NULL)
+ return;
+ if (vctxt->filename != NULL)
+ xmlFree(vctxt->filename);
+ if (filename != NULL)
+ vctxt->filename = (char *) xmlStrdup((const xmlChar *) filename);
+ else
+ vctxt->filename = NULL;
+}
+
+/**
+ * xmlSchemaClearValidCtxt:
+ * @vctxt: the schema validation context
*
* Free the resources associated to the schema validation context;
* leaves some fields alive intended for reuse of the context.
@@ -27552,6 +27591,11 @@
* where the user provides the dict?
*/
vctxt->dict = xmlDictCreate();
+
+ if (vctxt->filename != NULL) {
+ xmlFree(vctxt->filename);
+ vctxt->filename = NULL;
+ }
}
/**
@@ -27637,6 +27681,8 @@
xmlSchemaItemListFree(ctxt->nodeQNames);
if (ctxt->dict != NULL)
xmlDictFree(ctxt->dict);
+ if (ctxt->filename != NULL)
+ xmlFree(ctxt->filename);
xmlFree(ctxt);
}
@@ -28631,6 +28677,63 @@
}
/**
+ * xmlSchemaValidateSetLocator:
+ * @vctxt: a schema validation context
+ * @f: the locator function pointer
+ * @ctxt: the locator context
+ *
+ * Allows to set a locator function to the validation context,
+ * which will be used to provide file and line information since
+ * those are not provided as part of the SAX validation flow
+ * Setting @f to NULL disable the locator.
+ */
+
+void
+xmlSchemaValidateSetLocator(xmlSchemaValidCtxtPtr vctxt,
+ xmlSchemaValidityLocatorFunc f,
+ void *ctxt)
+{
+ if (vctxt == NULL) return;
+ vctxt->locFunc = f;
+ vctxt->locCtxt = ctxt;
+}
+
+/**
+ * xmlSchemaValidateStreamLocator:
+ * @ctx: the xmlTextReaderPtr used
+ * @file: returned file information
+ * @line: returned line information
+ *
+ * Internal locator function for the readers
+ *
+ * Returns 0 in case the Schema validation could be (des)activated and
+ * -1 in case of error.
+ */
+static int
+xmlSchemaValidateStreamLocator(void *ctx, const char **file,
+ unsigned long *line) {
+ xmlParserCtxtPtr ctxt;
+
+ if ((ctx == NULL) || ((file == NULL) && (line == NULL)))
+ return(-1);
+
+ if (file != NULL)
+ *file = NULL;
+ if (line != NULL)
+ *line = 0;
+
+ ctxt = (xmlParserCtxtPtr) ctx;
+ if (ctxt->input != NULL) {
+ if (file != NULL)
+ *file = ctxt->input->filename;
+ if (line != NULL)
+ *line = ctxt->input->line;
+ return(0);
+ }
+ return(-1);
+}
+
+/**
* xmlSchemaValidateStream:
* @ctxt: a schema validation context
* @input: the input to use for reading the data
@@ -28673,6 +28776,7 @@
xmlCtxtUseOptions(pctxt, options);
#endif
pctxt->linenumbers = 1;
+ xmlSchemaValidateSetLocator(ctxt, xmlSchemaValidateStreamLocator, pctxt);
inputStream = xmlNewIOInputStream(pctxt, input, enc);;
if (inputStream == NULL) {