Intereting Posts
PHP method = "post" перестает работать после того, как я добавил этот .htaccess … Почему? Как выбрать все имя столбца из таблицы в laravel? Производительность: запрос JSON и визуализация в JS или запрос всего HTML? Внутренняя ошибка сервера Как подавить предупреждение в файлах PHP для Netbeans? Печатать файлы, которые не доступны из www-root? Фильтр Yii2 на родственной модели, где имя отношения ниже camelCase Как это можно сделать с тем же результатом с помощью mysqli? Странное поведение в PHP и Apache2: разные выходные данные на разных серверах PHP INSERT – переменное количество записей в mysql из html-формы проблема с конкретной конфигурацией модуля zend Для этого адаптера требуется расширение PDO, но расширение не загружено .htaccess между разработкой, постановкой и производством move_uploaded_file Предупреждение: mysqli_connect (): (HY000 / 2002): php_network_getaddresses: getaddrinfo не удалось: никакой хост не известен

Выбор родительских узлов с помощью XMLReader

Мне пришлось переписать часть программы, чтобы использовать XMLReader для выбора частей XML-файла для обработки.

Возьмем этот упрощенный XML в качестве примера:

<odds> <sport> <region> <group> <event name="English Championship 2014-15" eventid="781016.1"> <bet name="Kazanan" betid="12377108.1"> <selection selectionid="52411062.1"/> </selection> </bet> </event> </group> </region> </sport> </odds> 

Этот вызов для xpath() :

 $bets = $xml->xpath( "//odds/sport/region/group/event/bet/selection[contains(@selectionid,'".$selectionToFind."')]/.." ); 

выберет весь узел <bet> и его дочерние узлы ( <selection> ).

Мой код, однако, выберет только один узел <selection> с заданным selectionid :

 $reader = new XMLReader; $reader->open('file.xml'); while($reader->read()) { $event = $reader->getAttribute($value); if ($event == 781016.1 ) { $node = new SimpleXMLElement($reader->readOuterXML()); var_dump($node); break; } } 

Как можно реплицировать поведение xpath() с помощью XMLReader чтобы я выбрал узел <bet> и его дочерние XMLReader , а не только один XMLReader <selection> ?

Я думаю, что вопрос сводится к следующему: могу ли я выбрать весь родительский узел <bet> по значению атрибута дочернего элемента, например <selection selectionid="[some_value]"> ?

[Игнорируйте решение SimpleXML и посмотрите на XMLReader]

Я бы предложил использовать метод SimpleXMLElement :: xpath.

http://php.net/manual/en/simplexmlelement.xpath.php

 $xml = new SimpleXMLElement($xml_string); /* Search for <a><b><c> */ $result = $xml->xpath("/odds/sport/region/group/event/bet"); 

$ result будет содержать всех детей с надписью «ставка».

// Решение XMLReader **********************

 $reader = new XMLReader; $reader->open('file.xml'); $parent_element = null; while($reader->read()) { $selectionid = $reader->getAttribute('selectionid'); if ($selectionid == '52411062.1' ) { // use the parent of the node with attribute 'selectionid' = '52411062.1' $node = $parent_element; var_dump($node); break; } elseif ($reader->name === 'bet') { ) { // store parent element $parent_element = new SimpleXMLElement($reader->readOuterXML()); } } 

DOMXPath считается более надежным, чем SimpleXML отношении производительности (он имеет другие преимущества, например, он может правильно обрабатывать пространства имен). См., Например, эту статью IBM для обсуждения нескольких библиотек XPath в PHP.

Мне просто интересно, если ваша проблема с производительностью будет сохраняться (или все еще быть такой же серьезной) при использовании DOMXPath :

 <?php $doc = new DOMDocument; $doc->load('sample.xml'); $xpath = new DOMXPath($doc); $nodes = $xpath->query("/odds/sport/region/group/event/bet[selection/@selectionid = '52411062.1']"); foreach ($nodes as $node) { print $xml = $node->ownerDocument->saveXML($node); } ?> 

Результат, взятый в качестве ввода небольшого фрагмента, который вы показали, является

 <bet name="Kazanan" betid="12377108.1"> <selection selectionid="52411062.1"/> </bet> 

Если это не поможет, вам действительно нужно прибегнуть к XML-парсеру, основанному на событиях (pull-style), который не читает весь документ в памяти, как предлагает Ясен.

XMLReader может expand() текущий узел в DOMNode . Это будет загружать только узел и его потомков в память.

После этого вы можете использовать экземпляр DOMXPath или преобразовать узел в SimpleXMLElement .

 $reader = new XMLReader(); $reader->open('data:/text/xml,'.urlencode($xml)); $dom = new DOMDocument(); $xpath = new DOMXpath($dom); while($reader->read()) { if ( $reader->nodeType == XMLReader::ELEMENT && $reader->localName == 'bet' ) { $bet= $reader->expand($dom); if ($xpath->evaluate('count(selection[@selectionid = "52411062.1"]) > 0', $bet)) { var_dump($dom->saveXml($bet)); } } } 

Вам всегда нужно будет решить, какую часть реализовать в XMLReader, а также в DOM / SimpleXML. В XMLReader вам придется проверять узлы и поддерживать состояние, но можно избежать загрузки данных. В какой-то момент разбора фрагменты XML будут достаточно малы, и вы можете использовать expand() .