来自资源与 noNamespaceSchemaLocation 的 Qt Schema 验证

Qt Schema validation from resource vs noNamespaceSchemaLocation

抱歉提前阅读了很长时间,我尽量保持简洁。请随时要求我详细说明某些方面,或编辑和删除某些部分以增强此问题。

背景:
我们有一个可以与许多模块(守护进程)交互的应用程序。 每个模块都是从数据库中的 XML 配置的。

当有人手动编辑 XML 配置(在总部和现场)时,我们有时不得不调试问题,所以我自己在运行时验证 XML,所以我们可以更早地发现这些配置问题:

/*---------------------------------------------------------------------------
**
*/
bool BaseApplication::validateXML(const QDomDocument& doc, const QString& schema)
{
    QFile xsdfile(schema);
    if (xsdfile.open(QFile::ReadOnly)) {

        QXmlSchema xsd;
        xsd.load(&xsdfile);

        if (xsd.isValid()) {
            QXmlSchemaValidator validator(xsd);

            const QString xml = doc.toString();
            return validator.validate(xml.toLatin1());
        }
        else {
            qWarning("BaseApplication::validateXML() - schema \"%s\" is not well-formed", qPrintable(schema));
        }
    }
    else {
        qWarning("BaseApplication::validateXML() - unable to open schema \"%s\"", qPrintable(schema));
    }

    return false;
}

所有模块都有一个派生自此 BaseApplication 的应用程序 class。它是更大框架的一部分。

所以 bootstrap 的应用程序可以做类似的事情:

void Application::preBegin()
{
    ...
    const QDomDocument config = // load XML from database

    if (!validateXML(config, ":schema.xsd")) {
        qFatal("Application::preBegin() - configuration is not valid");
    }
    ...
}

但是这样做仍然完全是可选的(每个模块)。 这在我们的工程环境中一切正常。

问题:
由于{原因过于复杂和分散注意力},设置和维护大型客户系统的部门编写了生成各种模块 XML 配置的脚本,以包括(除其他外)noNamespaceSchemaLocation.

所以典型的模块配置不是这样的:

<configuration>
  <!--XML struct here-->
</configuration>

它们是这样写的:

<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" schema_version="1" xsi:noNamespaceSchemaLocation="{url to XSD file on intranet server}">
  <!--XML struct here-->
</configuration>

(模块将这些额外属性视为元数据)

这会导致具有内置 XSD 验证的模块出现问题。在加载和验证模块的 XML 配置的运行时,我们看到了奇怪的行为(UB?)。即使这是单线程中的同步进程,调试日志也会显示在 Application::preBegin() 之前发生的事件应该在之后发生。 我们还看到在 XML 验证中丢失了整整一分钟(精确到秒)。

从根对象中手动删除 noNamespaceSchemaLocation 属性可以解决此问题。 然后验证立即发生,事件根据日志以正确的顺序发生。

问题:
是否有任何我可以添加到 BaseApplication::validateXML() 中的 /call 的内容,这可能会导致例程忽略它试图验证的 XML 中提及的任何 noNamespaceSchemaLocation

验证例程尝试解析 xml 架构位置时,1 分钟超时可能是 tcpip 超时。

您可以做的是在验证之前从配置文件中删除所有命名空间。将原始配置解析为 xml 文档,并让这个问题 How to remove all namespaces from XML with C#? 的解决方案从中删除名称空间。然后可以根据架构验证清理后的字符串结果。