Я пытаюсь и нуждаюсь в некоторой помощи, делая следующее:
Я хочу, чтобы поток обрабатывал большой 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); ?>