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.
my_schema.xsd
Description: XML document
<?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>