Mam następujący plik XML, plik jest dość duży i nie udało mi się otworzyć i odczytać pliku simplexml, więc próbuję XMLReader bez powodzenia w 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>
Niestety nie znalazłem dobrego samouczka na ten temat dla PHP i chciałbym zobaczyć, jak mogę uzyskać zawartość każdego elementu do przechowywania w bazie danych.
Odpowiedzi:
Wszystko zależy od tego, jak duża jest jednostka pracy, ale myślę, że próbujesz traktować każdy
<product/>
węzeł po kolei.W tym celu najprostszym sposobem byłoby użycie XMLReader, aby dostać się do każdego węzła, a następnie użyć SimpleXML, aby uzyskać do nich dostęp. W ten sposób utrzymujesz niskie zużycie pamięci, ponieważ przetwarzasz jeden węzeł na raz i nadal korzystasz z łatwości użytkowania SimpleXML. Na przykład:
$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'); }
Szybki przegląd zalet i wad różnych podejść:
Tylko XMLReader
Zalety: szybki, zużywa mało pamięci
Wady: zbyt trudne do napisania i debugowania, wymaga dużej ilości kodu w przestrzeni użytkownika, aby zrobić cokolwiek pożytecznego. Kod obszaru użytkownika jest powolny i podatny na błędy. Dodatkowo pozostawia ci więcej linii kodu do utrzymania
XMLReader + SimpleXML
Zalety: nie zajmuje dużo pamięci (tylko pamięć potrzebna do przetworzenia jednego węzła), a SimpleXML jest, jak sama nazwa wskazuje, naprawdę łatwy w użyciu.
Wady: tworzenie obiektu SimpleXMLElement dla każdego węzła nie jest zbyt szybkie. Naprawdę musisz to porównać, aby zrozumieć, czy to dla ciebie problem. Jednak nawet skromna maszyna byłaby w stanie przetworzyć tysiąc węzłów na sekundę.
XMLReader + DOM
Zalety: zużywa mniej więcej tyle pamięci co SimpleXML, a XMLReader :: expand () jest szybsze niż tworzenie nowego elementu SimpleXMLE. Chciałbym, żeby było to możliwe,
simplexml_import_dom()
ale w tym przypadku wydaje się, że nie działaWady: praca z DOM jest irytująca. Jest w połowie drogi między XMLReader i SimpleXML. Nie tak skomplikowane i niewygodne jak XMLReader, ale lata świetlne od pracy z SimpleXML.
Moja rada: napisz prototyp za pomocą SimpleXML, sprawdź, czy zadziała. Jeśli najważniejsza jest wydajność, wypróbuj DOM. Trzymaj się jak najdalej od XMLReadera. Pamiętaj, że im więcej napiszesz kodu, tym większe prawdopodobieństwo wprowadzenia błędów lub regresji wydajności.
źródło
W przypadku XML sformatowanego przy użyciu atrybutów ...
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>
kod 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();
źródło
Zaakceptowana odpowiedź dała mi dobry początek, ale przyniosła więcej zajęć i więcej przetwarzania, niż bym chciał; więc oto moja interpretacja:
$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();
źródło
Większość mojego życia na analizowaniu XML spędzam na wydobywaniu fragmentów przydatnych informacji z ciężarówek XML (Amazon MWS). W związku z tym moja odpowiedź zakłada, że chcesz tylko określonych informacji i wiesz, gdzie się one znajdują.
Uważam, że najłatwiejszym sposobem korzystania z XMLReader jest wiedzieć, z których tagów chcę usunąć informacje i ich używać. Jeśli znasz strukturę XML i zawiera on wiele unikalnych tagów, stwierdzam, że użycie pierwszego przypadku jest łatwe. Przypadki 2 i 3 mają po prostu pokazać, jak można to zrobić w przypadku bardziej złożonych tagów. To jest niezwykle szybkie; Mam dyskusję na temat szybkości. Jaki jest najszybszy parser XML w PHP?
Najważniejszą rzeczą do zapamiętania podczas przeprowadzania analizowania opartego na tagach, takiego jak ten, jest użycie
if ($myXML->nodeType == XMLReader::ELEMENT) {...
- które sprawdza, czy mamy do czynienia tylko z otwieranymi węzłami, a nie z białymi znakami, zamykającymi węzłami lub czymkolwiek.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(); }
źródło
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)); } }
źródło
XMLReader jest dobrze udokumentowany nastronie PHP . To jest XML Pull Parser, co oznacza, że jest używany do iteracji przez węzły (lub węzły DOM) danego dokumentu XML. Na przykład możesz przejrzeć cały przekazany dokument w ten sposób:<?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(); ?>
Od Ciebie zależy, jak postąpić z węzłem zwróconym przez XMLReader :: expand () .
źródło
To działa lepiej i szybciej dla mnie
<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>
** Plik zaplecza **
<?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>"); } ?>
źródło