尝试使用libxml2用xsd文件验证xml文件



我正在创建一个工具,该工具获取包含由其他程序生成的set工具的输入数据的xml文件。在使用这个输入数据之前,我应该验证xml文件,确保所有的数据都在那里。我正在尝试创建一个xsd文件来进行验证(使用libxml2库)。

试图验证这一点的c++代码目前还相当初级:

XmlValidator inputXmlValidator{};
res = inputXmlValidator.ConfigureValidationSchema("../temp_test_inputs/xml_validation/input.xsd");
if (!res)
return -1;
res = xmlValidator.ValidateXml("../temp_test_inputs/xml_validation/input.xml");
if (!res)
return -1;
bool XmlValidator::ConfigureValidationSchema(const char* xsdFilename)
{
if (schemaValidationContext != nullptr)
{
F1_ERROR("This instance already has a validation scheme configured!");
return false; // there is already a schema present...
}

xmlSchemaParserCtxtPtr schemaParserContext = nullptr;
schemaParserContext = xmlSchemaNewParserCtxt(xsdFilename);
if (schemaParserContext)
{
xmlSchemaPtr parsedSchema = nullptr;
xmlSchemaSetParserStructuredErrors(schemaParserContext, ProcessParsingError, nullptr);
parsedSchema = xmlSchemaParse(schemaParserContext);
xmlSchemaFreeParserCtxt(schemaParserContext);
if (parsedSchema)
schemaValidationContext = xmlSchemaNewValidCtxt(parsedSchema);
}
return schemaValidationContext != nullptr;
}
bool XmlValidator::ValidateXml(const char* xmlFilename)
{
if (schemaValidationContext == nullptr)
{
F1_ERROR("No validation scheme configured! Failed to validate '{0}'.", xmlFilename);
return false; // there is no validation schema present...
}
// read the xml file
xmlTextReaderPtr xmlTextReader = xmlReaderForFile(xmlFilename, NULL, 0);
if (xmlTextReader == nullptr)
{
F1_ERROR("Failed to open '{0}'.", xmlFilename);
return false; // failed to read xml file...
}
// configure schema validation
int hasSchemeErrors = 0;
xmlTextReaderSchemaValidateCtxt(xmlTextReader, schemaValidationContext, 0);
xmlSchemaSetValidStructuredErrors(schemaValidationContext, ProcessValidatorError, &hasSchemeErrors);
// process the xml file
int hasValidationErrors = 0;
do
{
hasValidationErrors = xmlTextReaderRead(xmlTextReader);
} while (hasValidationErrors == 1 && !hasSchemeErrors);
// process errors
//if (hasValidationErrors != 0)
//{
//    xmlErrorPtr err = xmlGetLastError();
//    F1_ERROR("Failed to parse '{0}' at line {1}, col {2}! Error {3}: {4}", err->file, err->line, err->int2, err->code, err->message);
//}
// free up the text reader memory
xmlFreeTextReader(xmlTextReader);
return hasValidationErrors == 0; // return true if no errors found
}

我很确定这段代码可以工作,因为我用shiporder示例尝试过它。现在我尝试离开这个示例,并将其更改为我自己的xml文件。

我使用了最基本的xml文件(只有根元素和一个属性)

<?xml version="1.0" encoding="UTF-8"?>
<root timestamp="20220714 1324">
</root>

我不能创建一个合适的xsd文件来验证这个:

<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema elementFormDefault="qualified" attributeFormDefault="unqualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema" >
<xs:element name="root">
<xs:complexType>
<xs:attribute type="xs:string" name="timestamp"/>
</xs:complexType>
</xs:element>
</xs:schema>

我一直得到错误Failed to validate '../temp_test_inputs/xml_validation/input.xml' at line 2, col 0! Error 1845: Element 'root': No matching global declaration available for the validation root.

经过3天的搜索,我找不到任何比这个错误更进一步的解决方案…什么好主意吗?在需要时,我可以修改xml文件,但最好只调整xsd文件(如果可能的话)。在这一点上,我接受任何解决办法……

我发现了错误…当然,这是一个愚蠢的…

我的main函数应该看起来像

auto res = xmlValidator.ConfigureValidationSchema("../temp_test_inputs/xml_validation/shiporder.xsd");
if (!res)
return -1;
res = xmlValidator.ValidateXml("../temp_test_inputs/xml_validation/shiporder.xml");
if (!res)
return -1;
F1_TEST_COMMON::XmlValidator inputXmlValidator{};
res = inputXmlValidator.ConfigureValidationSchema("../temp_test_inputs/xml_validation/input.xsd");
if (!res)
return -1;
res = inputXmlValidator.ValidateXml("../temp_test_inputs/xml_validation/input.xml");
if (!res)
return -1;

然而,它有一个"小"错误,它使用的是shiporder.xsd(xmlValidator)而不是input.xsd(inputXmlValidator)…

xmlValidator.ValidateXml("../temp_test_inputs/xml_validation/input.xml");

复制粘贴时只有一个变量错误…浪费了一个多星期的调试时间…