3

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

测试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>

首先,我尝试使用以下命令读取 test.xml 的内容QDomDocument

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 模块不支持外部实体?

4

1 回答 1

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。使用QXmlStreamReaderQXmlStreamWriter编写 XInclude 处理器相当简单。

这是我编写的一个基本的 Qt XInclude 处理器,它只执行一个级别的包含,但我相信您可以扩展它以合理轻松地支持递归包含。

一旦你有一个完全解析的 XML 文档,你应该能够使用QXmlSchemaValidator来验证它。

于 2013-09-29T20:06:15.847 回答