加快一批针对相同的XML模式的XML文件的XML模式验证(XSD)(Speeding up XML

2019-08-04 02:24发布

我想,以加快验证了一批XML文件对同一个XML模式(XSD)的过程。 唯一的限制是,我在PHP环境。

我现在的问题是,我想验证对架构包含的2755线(http://www.w3.org/2002/08/xhtml/xhtml1-transitional.xsd)的相当复杂的XHTML模式。 即使对于非常简单的数据这需要很长的时间(大约30秒PR。验证)。 由于我有成千上万的XML文件在我的批处理,这并不能真正很好地扩展。

为了验证XML文件我用这两种方法,从标准的PHP的XML库。

  • DOM文档:: schemaValidate
  • DOM文档:: schemaValidateSource

我想到的是,PHP实现抓取通过HTTP XHTML模式,并建立了一些内部表示(可能是一个DOMDocument),而这是扔掉完成验证时。 我想,对于XML的库某些选项可能会改变这种行为,在此过程中重复使用缓存的东西。

我已经建立一个简单的测试设置这说明我的问题:

测试schema.xsd

<xs:schema attributeFormDefault="unqualified"
    elementFormDefault="qualified"
    targetNamespace="http://myschema.example.com/"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:myschema="http://myschema.example.com/"
    xmlns:xhtml="http://www.w3.org/1999/xhtml">
    <xs:import
        schemaLocation="http://www.w3.org/2002/08/xhtml/xhtml1-transitional.xsd"
        namespace="http://www.w3.org/1999/xhtml">
    </xs:import>
    <xs:element name="Root">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="MyHTMLElement">
                    <xs:complexType>
                        <xs:complexContent>
                            <xs:extension base="xhtml:Flow"></xs:extension>
                        </xs:complexContent>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

测试data.xml中

<?xml version="1.0" encoding="UTF-8"?>
<Root xmlns="http://myschema.example.com/" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xml="http://www.w3.org/XML/1998/namespace" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://myschema.example.com/ test-schema.xsd ">
  <MyHTMLElement>
    <xhtml:p>This is an XHTML paragraph!</xhtml:p>
  </MyHTMLElement>
</Root>

schematest.php

<?php
$data_dom = new DOMDocument();
$data_dom->load('test-data.xml');

// Multiple validations using the schemaValidate method.
for ($attempt = 1; $attempt <= 3; $attempt++) {
    $start = time();
    echo "schemaValidate: Attempt #$attempt returns ";
    if (!$data_dom->schemaValidate('test-schema.xsd')) {
        echo "Invalid!";
    } else {
        echo "Valid!";
    }
    $end = time();
    echo " in " . ($end-$start) . " seconds.\n";
}

// Loading schema into a string.
$schema_source = file_get_contents('test-schema.xsd');

// Multiple validations using the schemaValidate method.
for ($attempt = 1; $attempt <= 3; $attempt++) {
    $start = time();
    echo "schemaValidateSource: Attempt #$attempt returns ";
    if (!$data_dom->schemaValidateSource($schema_source)) {
        echo "Invalid!";
    } else {
        echo "Valid!";
    }
    $end = time();
    echo " in " . ($end-$start) . " seconds.\n";
}

运行此文件schematest.php产生以下的输出:

schemaValidate: Attempt #1 returns Valid! in 30 seconds.
schemaValidate: Attempt #2 returns Valid! in 30 seconds.
schemaValidate: Attempt #3 returns Valid! in 30 seconds.
schemaValidateSource: Attempt #1 returns Valid! in 32 seconds.
schemaValidateSource: Attempt #2 returns Valid! in 30 seconds.
schemaValidateSource: Attempt #3 returns Valid! in 30 seconds.

任何帮助,并就如何解决这一问题的建议,非常欢迎!

Answer 1:

您可以安全地从时序值的开销。减去30秒。

到W3C服务器的远程请求被推迟,因为大多数图书馆不反映缓存文件(甚至是HTTP头提示)。 但是看了你的自己 :

W3C的服务器迟迟没有回来的DTD。 是延迟故意的吗?

是。 由于各种软件系统下载从我们的网站上百万次,每天的DTD(尽管我们的服务器的缓存指令),我们已经开始为来自我们的网站DTD和架构(DTD,XSD,耳鼻喉科,MOD等)与人为延迟。 我们这样做的目标是让更多人注意到我们与过度DTD流量持续存在的问题,并保护我们网站的其余部分的稳定性和响应时间。 我们建议HTTP缓存或目录文件来提高性能。

W3.org试图保持请求低。 这是可以理解的。 PHP的DomDocument是基于libxml的。 和libxml的允许设置外部实体装载机。 整个目录支撑部分是在这种情况下有趣。

为了解决这个问题的问题,建立一个catalog.xml文件:

<?xml version="1.0"?>
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
    <system systemId="http://www.w3.org/2002/08/xhtml/xhtml1-transitional.xsd"
            uri="xhtml1-transitional.xsd"/>
    <system systemId="http://www.w3.org/2001/xml.xsd"
            uri="xml.xsd"/>
</catalog>

这两个副本保存.xsd与该目录文件中给出的名称的文件旁边的目录(相对和绝对路径file:///...做的工作,如果你喜欢一个不同的目录)。

然后确保您的系统环境变量XML_CATALOG_FILES设置为的文件名catalog.xml文件。 当一切都设置,验证只是贯穿:

schemaValidate: Attempt #1 returns Valid! in 0 seconds.
schemaValidate: Attempt #2 returns Valid! in 0 seconds.
schemaValidate: Attempt #3 returns Valid! in 0 seconds.
schemaValidateSource: Attempt #1 returns Valid! in 0 seconds.
schemaValidateSource: Attempt #2 returns Valid! in 0 seconds.
schemaValidateSource: Attempt #3 returns Valid! in 0 seconds.

如果仍然需要很长的,它只是一个迹象,表明环境变量没有设置到正确的位置。 我已经处理变量以及一些边缘情况,以及在一篇博客文章:

  • 使用目录的验证与PHP的DOM文档和libxml2的

而应采取的不同的边缘情况护理,像含有空格的文件名。

可替换地,可以创建一个使用URL =>本地文件系统以阵列的形式的文件映射一个简单的外部实体装载机回调函数:

$mapping = [
     'http://www.w3.org/2002/08/xhtml/xhtml1-transitional.xsd'
         => 'schema/xhtml1-transitional.xsd',

     'http://www.w3.org/2001/xml.xsd'                          
         => 'schema/xml.xsd',
];

由于这表明,我已经放在这两个XSD文件的逐字拷贝到一个名为的子目录schema 。 下一步就是要利用libxml_set_external_entity_loader ,激活与映射的回调函数。 在磁盘上的文件存在已经是首选,并直接装填。 如果程序遇到非文件不具有映射,一个RuntimeException将有详细消息抛出:

libxml_set_external_entity_loader(
    function ($public, $system, $context) use ($mapping) {

        if (is_file($system)) {
            return $system;
        }

        if (isset($mapping[$system])) {
            return __DIR__ . '/' . $mapping[$system];
        }

        $message = sprintf(
            "Failed to load external entity: Public: %s; System: %s; Context: %s",
            var_export($public, 1), var_export($system, 1),
            strtr(var_export($context, 1), [" (\n  " => '(', "\n " => '', "\n" => ''])
        );

        throw new RuntimeException($message);
    }
);

设置这个外部实体装载机后,没有任何更长的远程请求的延迟。

仅此而已。 见要点 。 小心:这个外部实体加载器加载XML文件从磁盘验证和“解决”的XSD URI来本地文件名被写入。 其他类型的操作(例如,基于DTD验证)可能需要一些代码更改/扩展。 更优选的是XML目录。 这也适用于不同的工具。



Answer 2:

作为替代@hakre:下载第一次尝试外部资源(DTD),使用下载的版本算账:

libxml_set_external_entity_loader(    
    function ($public, $system, $context) {
        if(is_file($system)){
            return $system;
        }
        $cached_file= tempnam(sys_get_temp_dir(), md5($system));
        if (is_file($cached_file)) {
            return $cached_file;
        }
        copy($system,$cached_file);
        return $cached_file;
    }
);


文章来源: Speeding up XML schema validations of a batch of XML files against the same XML schema (XSD)