Поток разделяет XML-файл на 4 ГБ в PHP

Я пытаюсь и нуждаюсь в некоторой помощи, делая следующее:

Я хочу, чтобы поток обрабатывал большой XML-файл (4 ГБ) с PHP. Я не могу использовать простой 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> 

Я пытаюсь получить / скопировать все дочерние элементы каждого элемента <doc> в новый XML-файл, кроме элемента <links> и его дочерних элементов.

Поэтому я хочу, чтобы новый 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-файл, а затем записывая часть его содержимого в новый XML-файл на PHP.

Вот попытка колледжа. Это предполагает, что файл используется и что вы хотите записать в файл:

 <?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(); ?> в <?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(); ?> 

Для этого сценария вы не можете позволить себе использовать парсер DOM, как вы сказали, он не поместится в памяти из-за размера файла, и даже если бы вы могли, он будет медленным, так как он сначала загружает весь файл и после что вы должны проходить через нее, поэтому для этого случая вы должны попробовать парсер SAX (ориентированный на события / поток), добавить обработчик для тех тегов, в которые вы оказались ( doc , title , url , abstract ) и для каждого события добавьте узел, найденный в новый файл XML.

Здесь у вас есть дополнительная информация:

Каков самый быстрый XML-парсер в 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); ?>