【问题标题】:Stream parse 4 GB XML file in PHP在 PHP 中流解析 4 GB XML 文件
【发布时间】:2013-09-02 08:07:58
【问题描述】:

我正在尝试并需要一些帮助来执行以下操作:

我想用 PHP 流式解析一个大的 XML 文件(4 GB)。我不能使用简单的 XML 或 DOM,因为它们会将整个文件加载到内存中,所以我需要可以流式传输文件的东西。

我如何在 PHP 中做到这一点?

我想要做的是浏览一系列<doc> 元素。并将他们的一些孩子写入一个新的 xml 文件。

我尝试解析的 XML 文件如下所示:

<feed>
    <doc>
        <title>Title of first doc is here</title>
        <url>URL is here</url>
        <abstract>Abstract is here...</abstract>
        <links>
            <sublink>Link is here</sublink>
            <sublink>Link is here</sublink>
            <sublink>Link is here</sublink>
            <sublink>Link is here</sublink>
            <sublink>Link is here</sublink>
       </link>
    </doc>
    <doc>
        <title>Title of second doc is here</title>
        <url>URL is here</url>
        <abstract>Abstract is here...</abstract>
        <links>
            <sublink>Link is here</sublink>
            <sublink>Link is here</sublink>
            <sublink>Link is here</sublink>
            <sublink>Link is here</sublink>
            <sublink>Link is here</sublink>
       </link>
    </doc>
</feed>

我正在尝试将每个 &lt;doc&gt; 元素的所有子元素获取/复制到一个新的 XML 文件中,&lt;links&gt; 元素及其子元素除外。

所以我希望新的 XML 文件看起来像:

<doc>
    <title>Title of first doc is here</title>
    <url>URL is here</url>
    <abstract>Abstract is here...</abstract>
</doc>
<doc>
    <title>Title of second doc is here</title>
    <url>URL is here</url>
    <abstract>Abstract is here...</abstract>
</doc>

非常感谢流式传输/流式解析/流式读取原始 XML 文件,然后将其部分内容写入 PHP 中的新 XML 文件。

【问题讨论】:

  • 查看 XMLReader 类:php.net/manual/en/intro.xmlreader.php 这是一个流解析器。我现在正在更深入地阅读您的问题,看看是否可以提供更具体的答案。
  • @DeeDee 我听说过 XMLReader,但不知道如何使用它。感谢您的帮助!
  • 当然!正如官方文档中缺乏 cmets 所证明的那样,它并没有被过多地使用。我自己已经很长时间没有使用它了。你能告诉我我的代码是如何工作的吗?如果它不能立即起作用,我们可以合作并找出问题所在。
  • @DeeDee 是的,当然。今晚晚些时候我会试一试,让你知道它是否有效或我得到任何错误。感谢您帮助我并愿意合作直到问题解决:-)
  • 还有.. 为什么关闭了?我很确定这个问题是关于 php、xml、xml 解析、大文件的主题.. wtf

标签: php xml xml-parsing large-files large-data


【解决方案1】:

这是一个大学尝试。这假设正在使用一个文件,并且您想要写入一个文件:

<?php

$interestingNodes = array('title','url','abstract');
$xmlObject = new XMLReader();
$xmlObject->open('bigolfile.xml');

$xmlOutput = new XMLWriter();
$xmlOutput->openURI('destfile.xml');
$xmlOutput->setIndent(true);
$xmlOutput->setIndentString("   ");
$xmlOutput->startDocument('1.0', 'UTF-8');

while($xmlObject->read()){
    if($xmlObject->name == 'doc'){
        $xmlOutput->startElement('doc');
        $xmlObject->readInnerXML();
        if(array_search($xmlObject->name, $interestingNodes)){
             $xmlOutput->startElement($xmlObject->name);
             $xmlOutput->text($xmlObject->value);
             $xmlOutput->endElement(); //close the current node
        }
        $xmlOutput->endElement(); //close the doc node
    }
}

$xmlObject->close();
$xmlOutput->endDocument();
$xmlOutput->flush();

?>

【讨论】:

  • 您最近编辑的内容是什么?我无法分辨当前版本和我之前阅读的版本之间的区别。
  • 这看起来正是我想要的,谢谢。今晚晚些时候我会试一试,然后告诉你会发生什么。
  • 我关闭了&lt;?php标签
  • 啊,好的。因此,无需更改代码。今晚晚些时候我会试一试,然后告诉你进展如何。
  • 当我尝试运行仅包含您的代码的文件时出现错误。这是我在错误日志中得到的错误:PHP Fatal error: Call to undefined method XMLReader::startElement() in xml.php on line 15
【解决方案2】:

对于这种情况,您不能使用 DOM 解析器,正如您所说,由于文件大小,它不适合内存,即使可以,它也会很慢,因为它首先加载整个文件,然后您必须遍历它,因此,对于这种情况,您应该尝试 SAX 解析器(面向事件/流),为您感兴趣的那些标签添加一个处理程序(doc,title,@ 987654324@, abstract) 并为每个事件附加在新 XML 文件中找到的节点。

这里有更多信息:

What is the fastest XML parser in PHP?

这是一个(未测试)代码示例:

<?php
    $file = "bigfile.xml";
    $fh = fopen("out.xml", 'a') or die("can't open file");
    $currentNodeTag = "";    
    $tags = array("doc", "title", "url", "abstract");

    function startElement($parser, $name, $attrs) {
        global $tags;

        if (isset($tags[strtolower($name)])) {
            $currentNodeTag = strtolower($name);
            fwrite($fh, sprintf("<%s>\n"));
        }
    }

    function endElement($parser, $name) {
        global $tags;

        if (isset($tags[strtolower($name)])) {
            fwrite($fh, sprintf("</%s>\n"));
            $currentNodeTag = "";
        }
    }

    function characterData($parser, $data) {
        if (!empty($currentNodeTag)) {
            fwrite($fh, $data);
        }
    }    

    $xmlParser = xml_parser_create();
    xml_set_element_handler($xmlParser, "startElement", "endElement");
    xml_set_character_data_handler ($xmlParser, "characterData");

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

    while ($data = fread($fp, 4096)) {
        if (!xml_parse($xmlParser, $data, feof($fp))) {
            die(sprintf("XML error: %s at line %d",
                        xml_error_string(xml_get_error_code($xmlParser)),
                        xml_get_current_line_number($xmlParser)));
        }
    }

    xml_parser_free($xmlParser);
    fclose($fh);
?>

【讨论】:

  • 我遇到了一个似乎无法修复的代码错误。这也没有意义。我得到的错误是:`PHP Parse error: syntax error, unexpected ';'在第 12 行的 /Users/irfanm/Desktop/mamp/xml2.php 中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-07-15
  • 2018-11-26
  • 2014-12-06
  • 2020-06-16
  • 1970-01-01
  • 1970-01-01
  • 2012-12-22
相关资源
最近更新 更多