PHP:解析巨大的XML无内存

问题描述:

我想问,如果有人知道,如果有可能解析500 MB的XML。 问题看起来像那样。我有一个巨大的xml文件,它有很少的节点(可能不是很少,但与其中一个节点相比,它的确如此)) 其中一个节点是附件节点,它是基本64编码的。有可能,这个节点可能在500 MB左右。PHP:解析巨大的XML无内存

现在我的问题是否有解码它并写入文件而不会耗尽服务器内存不足的可能性?更改超过1GB的限制不是解决方法。

嗯,我在看xmlReader,但据我所见,我可以到达节点,我想解析,但然后我需要将节点保存到内存中,这是个坏主意。 我需要将此节点追加到文件而不读取它,但首先我需要解码它。

为了使它更有趣,我可能会得到这样的XML部分,但我打算写一个接一个的文件。 (将其追加到文件末尾)

而不是XMLReader使用XML Parser。它允许你通过块来分析xml,所以如果非常有效的话。这里是工作示例,它查找<ATTACHMENT>标签并将其内容解码到文件中。处理base64很简单,只要记住它会将每3个字符转换为4个字符的编码字符串,所以只要您提供的长度可以被4除尽,就可以连接解码结果。

<?php 

class ExtractAttachments { 

    private $parser; 
    private $tmpFile; 
    private $tmpHandle; 
    private $buffer; 

    private $files = array(); 

    public function __construct($xml) { 
     $this->parser = xml_parser_create('UTF-8'); 
     xml_set_object($this->parser, $this); 
     xml_set_element_handler($this->parser, 'tag_start', 'tag_end'); 
     xml_set_character_data_handler($this->parser, 'cdata'); 
     $handle = fopen($xml, 'rb'); 
     while($string = fread($handle, 4096)) { 
      xml_parse($this->parser, $string, false); 
     } 
     xml_parse($this->parser, '', true); 
     fclose($handle); 
     xml_parser_free($this->parser); 
    } 

    public function tag_start($parser, $tag, $attr) { 
     if($tag == 'ATTACHMENT') { 
      $this->tmpFile = tempnam(__DIR__, 'xml'); 
      $this->tmpHandle = fopen($this->tmpFile, 'wb'); 
     } 
    } 

    public function tag_end($parser, $tag) { 
     if($this->tmpHandle) { 
      if($this->buffer) { 
       fwrite($this->tmpHandle, base64_decode($this->buffer)); 
       $this->buffer = ''; 
      } 
      fclose($this->tmpHandle); 
      $this->tmpHandle = null; 
      $this->files[] = $this->tmpFile; 
     } 
    } 

    public function cdata($parser, $data) { 
     if ($this->tmpHandle) { 
      $data = trim($data); 
      if($this->buffer) { 
       $data = $this->buffer . $data; 
       $this->buffer = ''; 
      } 
      if (0 != ($modulo = strlen($data)%4)) { 
       $this->buffer = substr($data, -$modulo); 
       $data = substr($data, 0, -$modulo); 
      } 
      fwrite($this->tmpHandle, base64_decode($data)); 
     } 
    } 

    public function getFiles(){ 
     return $this->files; 
    } 
} 

$xml = new ExtractAttachments('large.xml'); 
$xml->getFiles(); 
+0

确实每个xml块($ string)都需要是有效的xml吗? – TarranJones