У меня есть файл размером 5 МБ xml
Я использую следующий код, чтобы получить все nodeValue
$dom = new DomDocument('1.0', 'UTF-8'); if(!$dom->load($url)) return; $games = $dom->getElementsByTagName("game"); foreach($games as $game) { }
Это занимает 76 секунд, и есть около 2000 games
. Есть ли какая-либо оптимизация или другое решение для получения данных?
Вы не должны использовать Document Object Model на больших XML-файлах, он предназначен для понятных для человека документов, а не для больших наборов данных!
Если вам нужен быстрый доступ, вы должны использовать XMLReader или SimpleXML.
XMLReader идеально подходит для синтаксического анализа целых документов, а SimpleXML имеет хорошую функцию XPath для быстрого восстановления данных.
Для XMLReader вы можете использовать следующий код:
<?php // Parsing a large document with XMLReader with Expand - DOM/DOMXpath $reader = new XMLReader(); $reader->open("tooBig.xml"); while ($reader->read()) { switch ($reader->nodeType) { case (XMLREADER::ELEMENT): if ($reader->localName == "game") { $node = $reader->expand(); $dom = new DomDocument(); $n = $dom->importNode($node,true); $dom->appendChild($n); $xp = new DomXpath($dom); $res = $xp->query("/game/title"); // this is an example echo $res->item(0)->nodeValue; } } } ?>
Вышеизложенное выведет все названия игр (при условии, что у вас есть /game/title
XML-структура).
Для SimpleXML вы можете использовать:
$xml = file_get_contents($url); $sxml = new SimpleXML($xml); $games = $sxml->xpath('/game'); // returns an array of SXML nodes foreach ($games as $game) { print $game->nodeValue; }
Однажды я написал статью в блоге об загрузке огромных XML-файлов с помощью XMLReader – вы, вероятно, можете использовать некоторые из них.
Использование DOM или SimpleXML не является опцией, так как обе загружают весь документ в память.
Вы можете использовать DOMXpath
для запросов, что намного быстрее, чем метод DOMDocument:: getElementsByTagName()
.
<?php $xpath = new \DOMXpath($dom); $games = $xpath->query("//game"); foreach ($games as $game) { // Code here }
В одном из моих тестов с довольно большим файлом этот подход занял <1 сек, чтобы завершить итерацию 24k элементов, тогда как метод DOMDocument:: getElementsByTagName()
принимал ~ 27 минут (и время, затраченное на итерацию к следующему объекту была экспоненциальной).