2014-02-27 97 views
-1

我想問,如果有人知道,如果有可能解析500 MB的XML。 問題看起來像那樣。我有一個巨大的xml文件,它有很少的節點(可能不是很少,但與其中一個節點相比,它的確如此)) 其中一個節點是附件節點,它是基本64編碼的。有可能,這個節點可能在500 MB左右。PHP:解析巨大的XML無內存

現在我的問題是否有解碼它並寫入文件而不會耗盡服務器內存不足的可能性?更改超過1GB的限制不是解決方法。

嗯,我在看xmlReader,但據我所見,我可以到達節點,我想解析,但然後我需要將節點保存到內存中,這是個壞主意。 我需要將此節點追加到文件而不讀取它,但首先我需要解碼它。

爲了使它更有趣,我可能會得到這樣的XML部分,但我打算寫一個接一個的文件。 (將其追加到文件末尾)

回答

2

而不是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