如何使用PHP顺序解析大型XML文件

tch*_*ore 0 php xml memory-management

我正在尝试使用simpleXML在php中解析一个中等大小的XML文件(6mb).该脚本从XML文件中获取每条记录,检查它是否已经被导入,如果没有,则将该记录更新/插入到我自己的数据库中.

问题是我经常遇到超出内存分配的致命错误:

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 256 bytes) in /.../system/database/drivers/mysql/mysql_result.php on line 162
Run Code Online (Sandbox Code Playgroud)

我通过使用以下行来增加最大内存分配来避免该错误(从此处开始提示):

ini_set('memory_limit', '-1');
Run Code Online (Sandbox Code Playgroud)

然而,然后我遇到60秒的最大执行时间,并且,无论出于何种原因,我的服务器(Mac OS X上的XAMPP)都不会让我增加那个时间(如果我尝试包含脚本,脚本就不会运行像:)这样的一行

set_time_limit(240);
Run Code Online (Sandbox Code Playgroud)

然而,这一切似乎都非常低效; 我不应该能够打破文件的顺序并按顺序处理它吗?在下面的控制器中,我有一个计数变量($ cycle)来跟踪我所在的记录,但我无法弄清楚如何实现它仍然不需要处理整个XML文件.

控制器(我正在使用CodeIgniter)具有以下基本结构:

    $f = base_url().'data/data.xml';
    if($data = file_get_contents($f))
    {
        $cycle = 0;
        $xml = new SimpleXMLElement($data);
        foreach($xml->person as $p)
        {

        //this makes a single call to db for single field based on id of record in XML file                
        if($this->_notImported('source',$p['id']))
            {
               //various process here, mainly breaking up the data for inserting into four different bales
            }
            $cycle++;
        }
    }
Run Code Online (Sandbox Code Playgroud)

有什么想法吗?

编辑

为了进一步了解我正在做的事情,我抓住每个元素和子元素的大部分属性并将它们插入到我的数据库中.例如,使用我的旧代码,我有这样的事情:

$insert = array('indiv_name' => $p['fullname'],
                                    'indiv_first' => ($p['firstname']),
                                    'indiv_last' => ($p['lastname']),
                                    'indiv_middle' => ($p['middlename']),
                                    'indiv_other' => ($p['namemod']),
                                    'indiv_full_name' => $full_name,
                                    'indiv_title' => ($p['title']),
                                    'indiv_dob' => ($p['birthday']),
                                    'indiv_gender' => ($p['gender']),
                                    'indiv_religion' => ($p['religion']),
                                    'indiv_url' => ($url)
                                    );
Run Code Online (Sandbox Code Playgroud)

有了使用XMLReader的建议(见下文),我怎样才能完成解析主元素和子元素的属性?

net*_*der 6

使用XMLReader.

说你的文件是这样的:

<test>
   <hello>world</hello>
   <foo>bar</foo>
</test>
Run Code Online (Sandbox Code Playgroud)

使用XMLReader:

$xml = new XMLReader;
$xml->open('doc.xml');

$xml->read();
while ($xml->read()) {
        if ($xml->nodeType == XMLReader::ELEMENT) {
                print $xml->name.': ';
        } else if ($xml->nodeType == XMLReader::TEXT) {
                print $xml->value.PHP_EOL;
        }
}
Run Code Online (Sandbox Code Playgroud)

这输出:

hello: world
foo: bar
Run Code Online (Sandbox Code Playgroud)

不错的是,您还可以使用expand将节点作为DOMNode对象获取.

  • 有很多方法可以做到这一点.最简单的是`getAttribute('attr_name')`.在`expand`之后,你也可以使用`moveToNextAttribute`或`DOMNode :: $ attributes`.但是,我真的认为第一个选择是要走的路.;) (2认同)