Xerces 4 and XML Schema 1.1 validation
Robert Hairgrove <[email protected]>
| Newsgroups | gmane.text.xml.xerces-c.devel |
|---|---|
| Message-ID | <[email protected]> |
The platforms I am using are Linux Ubuntu 18.04 with GCC 7.50 and
Windows 10. My C++ application (built with Qt libraries 5.15.5 for
Windows and Linux) links to Xerces-C++ as a library and performs
validation on a XML file used to configure the importing of CSV text
files against an embedded XSD schema file. Having used this setup with
Xerces-C++ version 3.2.3 and the XSD file formatted for XML Schema 1.0,
it works very well. The import of the data is done using the opensource
"libcsv" library (located on GitHub: https://github.com/rgamble/libcsv),
and I am performing validation on a per-field basis in the callback
function using the configuration from the XML file which validates,
among other things, against regular expressions and minimum/maximum
values, etc.
Now the documentation for Xerces-C++ states that validation with XML
Schema 1.1 is possible. I downloaded the sources for the latest version
from GitHub (Xerces version = 4.0.0) and built my application using
that. It appears that even now, one of the most useful new features of
XML Schema 1.1 (assertions) is not working quite the way it should.
I have attached a minimal test case of what I am trying to do: CSV files
can have column headers in their first line, or maybe not. So I have two
sets of column definitions, one for files with headers, and one for
headerless files. The <col> elements in the first set have a 'name'
attribute, which is the column header; the elements in the second set
have an 'ord' attribute which is basically just a sequential integer
telling the application in which order the column appears in the file.
So I cannot define the 'use' attribute in the XSD as "required" for
either attribute, but I wanted to add '<xs:assert
test="exists(@name|@ord)/>' after the list of <col> attributes, as you
can see from the attached example.
I tested this on the site mentioned in the Apache website for Xerces-C++
at https://www.softwarebytes.org/xmlvalidation/. It seems to work quite
well; when I remove one of the "ord" attributes so that neither "name"
nor "ord" appears, I get a validation error: "Assertion evaluation
('exists(@name|@ord)') for element 'col' on schema type
'#AnonType_colcolumnsimportfileroot' did not succeed." When I put it
back, it says it is valid.
On Xerces-C++ 4.0.0, using the same files, it throws no errors, neither
with the apparently valid XML nor the faulty one with the missing "ord"
attribute. I am using the Xerces SAX2XMLReader with both XML and XSD
passed in a memory buffer. However, I might be setting it up wrong? Here
is the relevant part of my parsing code (I left out the code for the
error handler which is correctly implemented; you can refer to the Qt
documentation for the QByteArray and QIODevice classes which set up the
buffers from the data in the file):
<snip>
// fi_xsd and fi_xml are of type QFileInfo:
bool retval = false;
QFile schema(fi_xsd.absoluteFilePath());
QFile xmlfile(fi_xml.absoluteFilePath());
QByteArray ba_xsd, ba_xml;
if (schema.open(QIODevice::ReadOnly)) {
ba_xsd = schema.readAll();
schema.close();
}
if (xmlfile.open(QIODevice::ReadOnly)) {
ba_xml = xmlfile.readAll();
xmlfile.close();
}
try {
xercesc::SAX2XMLReader *parser =
xercesc::XMLReaderFactory::createXMLReader();
xercesc::ErrorHandler *handler = new CErrorHandler();
xercesc::MemBufInputSource
inMemorySchemaSource(reinterpret_cast<const
XMLByte*>(ba_xsd.constData()), ba_xsd.size(), "/schema.xsd");
xercesc::MemBufInputSource inMemoryXMLSource(reinterpret_cast<const
XMLByte*>(ba_xml.constData()), ba_xml.size (), "/xml.xsd");
parser->loadGrammar(inMemorySchemaSource,
xercesc::Grammar::SchemaGrammarType, true);
parser->setFeature(xercesc::XMLUni::fgXercesUseCachedGrammarInParse, true);
parser->setFeature(xercesc::XMLUni::fgSAX2CoreValidation, true);
parser->setFeature(xercesc::XMLUni::fgSAX2CoreNameSpaces, true);
parser->setFeature(xercesc::XMLUni::fgXercesSchemaFullChecking, true);
parser->setProperty(xercesc::XMLUni::fgXercesSchemaExternalNoNameSpaceSchemaLocation,
const_cast<void*>(static_cast<const void*>("")));
parser->setErrorHandler(handler);
parser->parse(inMemoryXMLSource);
if (parser->getErrorCount() != 0) {
std::cout << "ERROR: XML file '" << xml_file_path_ << "' does not
conform to the schema" << std::endl;
} else {
std::cout << "Valid!" << std::endl;
retval = true;
}
}
catch (const xercesc::SAXParseException &) {
std::cout << "Unhandled SAXParseException was caught" << std::endl;
}
catch (const xercesc::SAXException &) {
std::cout << "Unhandled SAXException was caught" << std::endl;
}
return retval;
</snip>
In addition to the bits one has to add to the <xs:schema> element, is
there anything else I have to do to turn on 1.1 validation in Xerces?
Thank you.
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
my_schema.xsd
(application/xml, 2.7 KB) - not displayed
my_test.xml
(text/xml, 912 B)
<?xml version="1.0" encoding="UTF-8"?>
<root xsi:noNamespaceSchemaLocation="./my_schema.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<importfile linebreaks="CRLF" quotes="true" delimiter="SEMICOLON" maptable="professions_import" type="proflist" mimetype="text/csv" quotechar="DQ">
<columns columnheaders="true">
<col strict="true" name="ID" ignore="false" regexp="XGR7MSwyfQ==" max="63" min="1" type="uint" mapcolumn="id"/>
<col strict="false" name="Description" maxlen="255" ignore="false" regexp="W1xkXXsxLDJ9XHNcUys=" type="string" mapcolumn="descr"/>
</columns>
<columns columnheaders="false">
<col strict="true" ignore="false" regexp="XGR7MSwyfQ==" max="63" min="1" type="uint" mapcolumn="id"/>
<col maxlen="255" strict="false" ord="2" ignore="false" regexp="W1xkXXsxLDJ9XHNcUys=" type="string" mapcolumn="descr"/>
</columns>
</importfile>
</root>