Анализ XML с помощью PHP и XMLReader

Я пытаюсь разобрать очень большой XML-файл с PHP и XMLReader, но, похоже, не могу получить результаты, которые я ищу. В принципе, я ищу тонну информации, и если a содержит определенный zipcode, я бы хотел вернуть этот бит XML или продолжить поиск, пока не найдет этот zipcode. По сути, я буду разбивать этот большой файл на несколько небольших кусков, поэтому вместо того, чтобы смотреть на тысячи или миллионы групп информации, это будет, возможно, 10 или 20 лет.

Вот немного XML с тем, что я хотел бы

//search through xml <lineups country="USA"> //cache TX02217 as a variable <headend headendId="TX02217"> //cache Grande Gables at The Terrace as a variable <name>Grande Gables at The Terrace</name> //cache Grande Communications as a variable <mso msoId="17541">Grande Communications</mso> <marketIds> <marketId type="DMA">635</marketId> </marketIds> //check to see if any of the postal codes are equal to $pc variable that will be set in the php <postalCodes> <postalCode>11111</postalCode> <postalCode>22222</postalCode> <postalCode>33333</postalCode> <postalCode>78746</postalCode> </postalCodes> //cache Austin to a variable <location>Austin</location> <lineup> //cache all prgSvcID's to an array ie 20014, 10722 <station prgSvcId="20014"> //cache all channels to an array ie 002, 003 <chan effDate="2006-01-16" tier="1">002</chan> </station> <station prgSvcId="10722"> <chan effDate="2006-01-16" tier="1">003</chan> </station> </lineup> <areasServed> <area> //cache community to a variable $community <community>Thorndale</community> <county code="45331" size="D">Milam</county> //cache state to a variable ie TX <state>TX</state> </area> <area> <community>Thrall</community> <county code="45491" size="B">Williamson</county> <state>TX</state> </area> </areasServed> </headend> //if any of the postal codes matched $pc //echo back the xml from <headend> to </headend> //if none of the postal codes matched $pc //clear variables and move to next <headend> <headend> etc etc etc </headend> <headend> etc etc etc </headend> <headend> etc etc etc </headend> </lineups> 

PHP:

 <?php $pc = "78746"; $xmlfile="myFile.xml"; $reader = new XMLReader(); $reader->open($xmlfile); while ($reader->read()) { //search to see if groups contain $pc and echo info } 

Я знаю, что делаю это сложнее, чем должно быть, но я немного перегружен, пытаясь манипулировать таким большим файлом. Любая помощь приветствуется.

Чтобы получить большую гибкость с XMLReader я обычно создаю себе итераторы, которые могут работать с объектом XMLReader и предоставлять необходимые мне шаги .

Это начинается с простой итерации по всем узлам итерации над элементами, необязательно с определенным именем. Назовем последний XMLElementIterator беря читателя и имя элемента в качестве параметров.

В вашем сценарии я тогда создавал бы итератор, который возвращает SimpleXMLElement для текущего элемента, беря только элементы <headend> :

 require('xmlreader-iterators.php'); // https://gist.github.com/hakre/5147685 class HeadendIterator extends XMLElementIterator { const ELEMENT_NAME = 'headend'; public function __construct(XMLReader $reader) { parent::__construct($reader, self::ELEMENT_NAME); } /** * @return SimpleXMLElement */ public function current() { return simplexml_load_string($this->reader->readOuterXml()); } } 

Оборудованный этим итератором, остальная часть вашей работы – это, в основном, кусок пирога. Сначала загрузите файл размером 10 гигабайт:

 $pc = "78746"; $xmlfile = '../data/lineups.xml'; $reader = new XMLReader(); $reader->open($xmlfile); 

И затем проверьте, содержит ли элемент <headend> эту информацию, и если да, отобразите данные / XML:

 foreach (new HeadendIterator($reader) as $headend) { /* @var $headend SimpleXMLElement */ if (!$headend->xpath("/*/postalCodes/postalCode[. = '$pc']")) { continue; } echo 'Found, name: ', $headend->name, "\n"; echo "==========================================\n"; $headend->asXML('php://stdout'); } 

Это делает буквально то, что вы пытаетесь достичь: итерации над большим документом (который является удобным для памяти), пока вы не найдете интересующий вас элемент (ы). Затем вы обрабатываете конкретный элемент и это только XML; XMLReader::readOuterXml() – прекрасный инструмент здесь.

Примерный вывод:

 Found, name: Grande Gables at The Terrace ========================================== <?xml version="1.0"?> <headend headendId="TX02217"> <name>Grande Gables at The Terrace</name> <mso msoId="17541">Grande Communications</mso> <marketIds> <marketId type="DMA">635</marketId> </marketIds> <postalCodes> <postalCode>11111</postalCode> <postalCode>22222</postalCode> <postalCode>33333</postalCode> <postalCode>78746</postalCode> </postalCodes> <location>Austin</location> <lineup> <station prgSvcId="20014"> <chan effDate="2006-01-16" tier="1">002</chan> </station> <station prgSvcId="10722"> <chan effDate="2006-01-16" tier="1">003</chan> </station> </lineup> <areasServed> <area> <community>Thorndale</community> <county code="45331" size="D">Milam</county> <state>TX</state> </area> <area> <community>Thrall</community> <county code="45491" size="B">Williamson</county> <state>TX</state> </area> </areasServed> </headend> 

Изменить: О, вы хотите вернуть родительский кусок? Один момент.

Вот пример, чтобы вытащить все почтовые коды в массив.

http://codepad.org/kHss4MdV

 <?php $string='<lineups country="USA"> <headend headendId="TX02217"> <name>Grande Gables at The Terrace</name> <mso msoId="17541">Grande Communications</mso> <marketIds> <marketId type="DMA">635</marketId> </marketIds> <postalCodes> <postalCode>11111</postalCode> <postalCode>22222</postalCode> <postalCode>33333</postalCode> <postalCode>78746</postalCode> </postalCodes> <location>Austin</location> <lineup> <station prgSvcId="20014"> <chan effDate="2006-01-16" tier="1">002</chan> </station> <station prgSvcId="10722"> <chan effDate="2006-01-16" tier="1">003</chan> </station> </lineup> <areasServed> <area> <community>Thorndale</community> <county code="45331" size="D">Milam</county> <state>TX</state> </area> <area> <community>Thrall</community> <county code="45491" size="B">Williamson</county> <state>TX</state> </area> </areasServed> </headend></lineups>'; $dom = new DOMDocument(); $dom->loadXML($string); $xpath = new DOMXPath($dom); $elements= $xpath->query('//lineups/headend/postalCodes/*[text()=78746]'); if (!is_null($elements)) { foreach ($elements as $element) { echo "<br/>[". $element->nodeName. "]"; $nodes = $element->childNodes; foreach ($nodes as $node) { echo $node->nodeValue. "\n"; } } } 

Выходы:

 <br/>[postalCode]78746