使用Qt读取和验证外部实体的xml文档

时间:2013-09-19 15:25:10

标签: xml qt xsd xsd-validation

我正在尝试阅读并验证具有外部实体的xml文档。但是我在阅读和验证方面都没有成功。 我使用this创建了一个测试示例。

测试xml:

<?xml version="1.0" standalone="no" ?>
<!DOCTYPE doc [
<!ENTITY otherFile SYSTEM "otherFile.xml">
]>
<doc>&otherFile;</doc>

其他xml:

<baz>this is my content</baz>

测试xsd:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="doc">
    <xs:complexType>
    <xs:sequence>
      <xs:element ref="baz"/>
    </xs:sequence>
  </xs:complexType>
</xs:element>

<xs:element name="baz" type="xs:string"/>

</xs:schema>

首先,我尝试使用QDomDocument读取test.xml的内容:

QDomDocument doc;
doc.setContent(&testFile);
qDebug() << doc.toString();

但是在调试输出中,我从test.xml获取原始文本。外部实体未被替换。

然后我尝试针对test.xsd验证test.xml:

QXmlSchema schema;
bool res = schema.load(&xsdFile, QUrl::fromLocalFile(xsdPath));
if (res == true)
{
    QXmlSchemaValidator validator(schema);
    if (validator.validate(&xmlFile, QUrl::fromLocalFile(xmlPath)))
    {
        qDebug() << "xml" << xmlName << "is valid";
    }
    else
    {
    qDebug() << "xml" << xmlName << "is invalid";
    }
}

但验证失败,我收到以下错误:

Error XSDError in file:///..., at line 5, column 5: Element doc is missing child element.

我做错了什么或者Qt Xml模块不支持外部实体?

1 个答案:

答案 0 :(得分:4)

我已经为您了解了这一点,简短的回答是,如果您想要DTD SYSTEM实体支持,我认为您可能需要更改为使用不同的解析器和验证器。

Qt 4有三种不同的XML解析器:

有3种不同类型的解析器被认为过于复杂,所以移动到Qt 5时,XML模块已被弃用,推荐的解析器现在是 QXmlStreamReader 。这是一个非常容易使用的解析器(与 QXmlSimpleReader 不同),但内存使用率远低于 QDomDocument

因此,如果您在Qt中编写用于XML解析的新代码,即使您当前没有使用Qt 5,我强烈建议您使用 QXmlStreamReader

不幸的是,手册页注释:

  

QXmlStreamReader是一个格式良好的XML 1.0解析器,不包含外部解析实体。

这意味着,它无法解析您的SYSTEM实体。此外,在检查源代码之后,看起来不存在可用于拦截实体解析的任何“隐藏”钩子或方法。

如果要将外部XML文档包含到其他文档中,可能需要查看使用XInclude。使用 QXmlStreamReader QXmlStreamWriter编写XInclude处理器相当简单。

这是我写的basic Qt XInclude processor,它只包含一个级别,但我相信你可以扩展它以合理地轻松支持递归包含。

获得完全解析的XML文档后,您应该能够使用 QXmlSchemaValidator 对其进行验证。