У меня есть следующий XML-файл, файл довольно большой, и мне не удалось заставить simplexml открыть и прочитать файл, поэтому я безуспешно пытаюсь XMLReader в php
<?xml version="1.0" encoding="ISO-8859-1"?>
<products>
<last_updated>2009-11-30 13:52:40</last_updated>
<product>
<element_1>foo</element_1>
<element_2>foo</element_2>
<element_3>foo</element_3>
<element_4>foo</element_4>
</product>
<product>
<element_1>bar</element_1>
<element_2>bar</element_2>
<element_3>bar</element_3>
<element_4>bar</element_4>
</product>
</products>
К сожалению, я не нашел хорошего руководства по этому вопросу для PHP и хотел бы увидеть, как я могу получить содержимое каждого элемента для хранения в базе данных.
Ответы:
Все зависит от того, насколько велика единица работы, но я предполагаю, что вы пытаетесь
<product/>
последовательно обрабатывать каждый узел.Для этого самым простым способом было бы использовать XMLReader для доступа к каждому узлу, а затем использовать SimpleXML для доступа к ним. Таким образом, вы сохраняете низкий уровень использования памяти, потому что обрабатываете по одному узлу за раз, и вы по-прежнему пользуетесь простотой использования SimpleXML. Например:
$z = new XMLReader; $z->open('data.xml'); $doc = new DOMDocument; // move to the first <product /> node while ($z->read() && $z->name !== 'product'); // now that we're at the right depth, hop to the next <product/> until the end of the tree while ($z->name === 'product') { // either one should work //$node = new SimpleXMLElement($z->readOuterXML()); $node = simplexml_import_dom($doc->importNode($z->expand(), true)); // now you can use $node without going insane about parsing var_dump($node->element_1); // go to next <product /> $z->next('product'); }
Краткий обзор плюсов и минусов разных подходов:
Только XMLReader
Плюсы: быстро, мало памяти
Минусы: слишком сложно писать и отлаживать, требуется много пользовательского кода, чтобы делать что-нибудь полезное. Код пользовательского пространства медленный и подвержен ошибкам. Кроме того, это оставляет вам больше строк кода для поддержки
XMLReader + SimpleXML
Плюсы: не использует много памяти (только память, необходимая для обработки одного узла), а SimpleXML, как следует из названия, действительно прост в использовании.
Минусы: создание объекта SimpleXMLElement для каждого узла не очень быстро. Вам действительно нужно протестировать его, чтобы понять, является ли это проблемой для вас. Однако даже скромная машина сможет обрабатывать тысячу узлов в секунду.
XMLReader + DOM
Плюсы: использует примерно столько же памяти, сколько SimpleXML, а XMLReader :: expand () быстрее, чем создание нового SimpleXMLElement. Хотелось бы, чтобы это можно было использовать,
simplexml_import_dom()
но, похоже, в этом случае это не работаетМинусы: работа с DOM утомляет. Это что-то среднее между XMLReader и SimpleXML. Не такой сложный и неудобный, как XMLReader, но на много световых лет от работы с SimpleXML.
Мой совет: напишите прототип с SimpleXML, посмотрите, подойдет ли он вам. Если производительность превыше всего, попробуйте DOM. Держитесь как можно дальше от XMLReader. Помните, что чем больше кода вы напишете, тем выше вероятность появления ошибок или снижения производительности.
источник
Для xml, отформатированного с атрибутами ...
data.xml:
<building_data> <building address="some address" lat="28.902914" lng="-71.007235" /> <building address="some address" lat="48.892342" lng="-75.0423423" /> <building address="some address" lat="58.929753" lng="-79.1236987" /> </building_data>
PHP код:
$reader = new XMLReader(); if (!$reader->open("data.xml")) { die("Failed to open 'data.xml'"); } while($reader->read()) { if ($reader->nodeType == XMLReader::ELEMENT && $reader->name == 'building') { $address = $reader->getAttribute('address'); $latitude = $reader->getAttribute('lat'); $longitude = $reader->getAttribute('lng'); } $reader->close();
источник
Принятый ответ дал мне хорошее начало, но принес больше классов и больше обработки, чем мне хотелось бы; так что это моя интерпретация:
$xml_reader = new XMLReader; $xml_reader->open($feed_url); // move the pointer to the first product while ($xml_reader->read() && $xml_reader->name != 'product'); // loop through the products while ($xml_reader->name == 'product') { // load the current xml element into simplexml and we’re off and running! $xml = simplexml_load_string($xml_reader->readOuterXML()); // now you can use your simpleXML object ($xml). echo $xml->element_1; // move the pointer to the next product $xml_reader->next('product'); } // don’t forget to close the file $xml_reader->close();
источник
Большая часть моей жизни, связанной с синтаксическим анализом XML, уходит на извлечение кусков полезной информации из грузовиков XML (Amazon MWS). Таким образом, мой ответ предполагает, что вам нужна только конкретная информация и вы знаете, где она находится.
Я считаю, что самый простой способ использовать XMLReader - это знать, из каких тегов мне нужна информация, и использовать их. Если вы знаете структуру XML и в нем много уникальных тегов, я считаю, что использовать первый случай проще простого. Случаи 2 и 3 предназначены только для того, чтобы показать вам, как это можно сделать для более сложных тегов. Это очень быстро; У меня есть обсуждение скорости на тему « Какой самый быстрый синтаксический анализатор XML в PHP?»
Самая важная вещь, которую следует помнить при выполнении подобного синтаксического анализа на основе тегов, - это использовать
if ($myXML->nodeType == XMLReader::ELEMENT) {...
- который проверяет, что мы имеем дело только с открывающими узлами, а не с пробелами или закрывающими узлами или чем-то еще.function parseMyXML ($xml) { //pass in an XML string $myXML = new XMLReader(); $myXML->xml($xml); while ($myXML->read()) { //start reading. if ($myXML->nodeType == XMLReader::ELEMENT) { //only opening tags. $tag = $myXML->name; //make $tag contain the name of the tag switch ($tag) { case 'Tag1': //this tag contains no child elements, only the content we need. And it's unique. $variable = $myXML->readInnerXML(); //now variable contains the contents of tag1 break; case 'Tag2': //this tag contains child elements, of which we only want one. while($myXML->read()) { //so we tell it to keep reading if ($myXML->nodeType == XMLReader::ELEMENT && $myXML->name === 'Amount') { // and when it finds the amount tag... $variable2 = $myXML->readInnerXML(); //...put it in $variable2. break; } } break; case 'Tag3': //tag3 also has children, which are not unique, but we need two of the children this time. while($myXML->read()) { if ($myXML->nodeType == XMLReader::ELEMENT && $myXML->name === 'Amount') { $variable3 = $myXML->readInnerXML(); break; } else if ($myXML->nodeType == XMLReader::ELEMENT && $myXML->name === 'Currency') { $variable4 = $myXML->readInnerXML(); break; } } break; } } } $myXML->close(); }
источник
Simple example: public function productsAction() { $saveFileName = 'ceneo.xml'; $filename = $this->path . $saveFileName; if(file_exists($filename)) { $reader = new XMLReader(); $reader->open($filename); $countElements = 0; while($reader->read()) { if($reader->nodeType == XMLReader::ELEMENT) { $nodeName = $reader->name; } if($reader->nodeType == XMLReader::TEXT && !empty($nodeName)) { switch ($nodeName) { case 'id': var_dump($reader->value); break; } } if($reader->nodeType == XMLReader::END_ELEMENT && $reader->name == 'offer') { $countElements++; } } $reader->close(); exit(print('<pre>') . var_dump($countElements)); } }
источник
XMLReader хорошо документирован насайте PHP . Это XML Pull Parser, что означает, что он используется для перебора узлов (или узлов DOM) данного XML-документа. Например, вы можете просмотреть весь предоставленный вами документ следующим образом:<?php $reader = new XMLReader(); if (!$reader->open("data.xml")) { die("Failed to open 'data.xml'"); } while($reader->read()) { $node = $reader->expand(); // process $node... } $reader->close(); ?>
Затем вам решать, как поступить с узлом, возвращаемым XMLReader :: expand () .
источник
Это работает лучше и быстрее для меня
<html> <head> <script> function showRSS(str) { if (str.length==0) { document.getElementById("rssOutput").innerHTML=""; return; } if (window.XMLHttpRequest) { // code for IE7+, Firefox, Chrome, Opera, Safari xmlhttp=new XMLHttpRequest(); } else { // code for IE6, IE5 xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); } xmlhttp.onreadystatechange=function() { if (this.readyState==4 && this.status==200) { document.getElementById("rssOutput").innerHTML=this.responseText; } } xmlhttp.open("GET","getrss.php?q="+str,true); xmlhttp.send(); } </script> </head> <body> <form> <select onchange="showRSS(this.value)"> <option value="">Select an RSS-feed:</option> <option value="Google">Google News</option> <option value="ZDN">ZDNet News</option> <option value="job">Job</option> </select> </form> <br> <div id="rssOutput">RSS-feed will be listed here...</div> </body> </html>
** Серверный файл **
<?php //get the q parameter from URL $q=$_GET["q"]; //find out which feed was selected if($q=="Google") { $xml=("http://news.google.com/news?ned=us&topic=h&output=rss"); } elseif($q=="ZDN") { $xml=("https://www.zdnet.com/news/rss.xml"); }elseif($q == "job"){ $xml=("https://ngcareers.com/feed"); } $xmlDoc = new DOMDocument(); $xmlDoc->load($xml); //get elements from "<channel>" $channel=$xmlDoc->getElementsByTagName('channel')->item(0); $channel_title = $channel->getElementsByTagName('title') ->item(0)->childNodes->item(0)->nodeValue; $channel_link = $channel->getElementsByTagName('link') ->item(0)->childNodes->item(0)->nodeValue; $channel_desc = $channel->getElementsByTagName('description') ->item(0)->childNodes->item(0)->nodeValue; //output elements from "<channel>" echo("<p><a href='" . $channel_link . "'>" . $channel_title . "</a>"); echo("<br>"); echo($channel_desc . "</p>"); //get and output "<item>" elements $x=$xmlDoc->getElementsByTagName('item'); $count = $x->length; // print_r( $x->item(0)->getElementsByTagName('title')->item(0)->nodeValue); // print_r( $x->item(0)->getElementsByTagName('link')->item(0)->nodeValue); // print_r( $x->item(0)->getElementsByTagName('description')->item(0)->nodeValue); // return; for ($i=0; $i <= $count; $i++) { //Title $item_title = $x->item(0)->getElementsByTagName('title')->item(0)->nodeValue; //Link $item_link = $x->item(0)->getElementsByTagName('link')->item(0)->nodeValue; //Description $item_desc = $x->item(0)->getElementsByTagName('description')->item(0)->nodeValue; //Category $item_cat = $x->item(0)->getElementsByTagName('category')->item(0)->nodeValue; echo ("<p>Title: <a href='" . $item_link . "'>" . $item_title . "</a>"); echo ("<br>"); echo ("Desc: ".$item_desc); echo ("<br>"); echo ("Category: ".$item_cat . "</p>"); } ?>
источник