在PHP中验证大型XML文件~400MB

时间:2012-12-13 10:41:07

标签: php xml xml-parsing out-of-memory xmlreader

我有一个大的XML文件(大约400MB),我需要确保在开始处理之前格式良好。

我尝试过的第一件事就是下面的内容,这很棒,因为我可以看出XML是否格式不正确以及XML的哪些部分是“坏”

$doc = simplexml_load_string($xmlstr);
if (!$doc) {
    $errors = libxml_get_errors();

    foreach ($errors as $error) {
        echo display_xml_error($error);
    }

    libxml_clear_errors();
}

还试过......

$doc->load( $tempFileName, LIBXML_DTDLOAD|LIBXML_DTDVALID )

我用大约60MB的文件测试了这个,但是任何更大的东西(~400MB)都会让我感到陌生的“oom杀手”在看起来像30秒之后开始并终止脚本。

我认为我可能需要增加脚本的内存,以便在处理60MB时计算出峰值使用率,并相应地调整它的大小,并将脚本时间限制关闭以防万一。

set_time_limit(0);
ini_set('memory_limit', '512M');

不幸的是,这不起作用,因为如果内存负载(即使是正确的术语?)一直很高,那么oom杀手似乎是一个linux的东西。

如果我能以某种方式加载xml,这将是很好的,因为我想这将减少内存负载,以便oom杀手不会粘住它的胖鼻子并杀死我的进程。

有没有人有任何验证大型XML文件和捕获错误形成错误的经验,我读过很多帖子都指向可能解决我问题的SAX和XMLReader。

更新 所以@chiborg对我来说几乎解决了这个问题...这个方法唯一的缺点就是我没有看到文件中的所有错误,只是第一个失败,我认为这是有意义的,因为我认为它无法解析失败的第一个点。

当使用simplexml时...它能够捕获文件中的大部分问题,并在最后显示我很好。

2 个答案:

答案 0 :(得分:6)

由于SimpleXML和DOM API将始终将文档加载到内存中,因此使用SAX或XMLReader等流式解析器是更好的方法。

使用example page中的代码,它可能如下所示:

$xml_parser = xml_parser_create();
if (!($fp = fopen($file, "r"))) {
    die("could not open XML input");
}

while ($data = fread($fp, 4096)) {
    if (!xml_parse($xml_parser, $data, feof($fp))) {
        $errors[] = array(
                    xml_error_string(xml_get_error_code($xml_parser)),
                    xml_get_current_line_number($xml_parser));
    }
}
xml_parser_free($xml_parser);

答案 1 :(得分:0)