tutorial leer imprimir create crear con array archivo php xml parsing simplexml xmlreader

leer - ¿Cómo usar XMLReader en PHP?



simplexml php (8)

Tengo el siguiente archivo XML, el archivo es bastante grande y no he podido obtener simplexml para abrir y leer el archivo, así que estoy intentando XMLReader sin éxito en 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>

Desafortunadamente, no he encontrado un buen tutorial sobre PHP y me gustaría ver cómo puedo obtener el contenido de cada elemento para almacenarlo en una base de datos.


Este tema se abandonó hace mucho tiempo, pero lo acabo de encontrar. Gracias a Dios.

Mi problema es que tengo que leer el archivo ONIX (datos del libro) y almacenarlo en nuestra base de datos. Yo uso simplexml_load antes, y aunque usé mucha memoria pero todavía está bien para archivos relativamente pequeños (hasta 300MB). Más allá de ese tamaño es un desastre para mí.

Después de leer, especialmente la interpretación de Francis Lewis, utilizo la combinación de xmlreader y simplexml. El resultado es excepcional, el uso de memoria es pequeño y lo inserto en la base de datos lo suficientemente rápido para mí.

Aquí está mi código:

<?php $dbhost = "localhost"; // mysql host $dbuser = ""; //mysql username $dbpw = ""; // mysql user password $db = ""; // mysql database name //i need to truncate the old data first $conn2 = mysql_connect($dbhost, $dbuser, $dbpw); mysql_select_db($db); mysql_query ("truncate ebiblio",$conn2); //$xmlFile = $_POST[''xmlFile'']; //$xml=simplexml_load_file("ebiblio.xml") or die("Error: Cannot create object"); $reader = new XMLReader(); //load the selected XML file to the DOM if (!$reader->open("ebiblio.xml")) { die("Failed to open ''ebiblio.xml''"); } while ($reader->read()): if ($reader->nodeType == XMLReader::ELEMENT && $reader->name == ''product''){ $xml = simplexml_load_string($reader->readOuterXML()); $productcode = (string)$xml->a001; $title = (string)$xml->title->b203; $author = (string)$xml->contributor->b037; $language = (string)$xml->language->b252; $category = $xml->subject->b069; $description = (string)$xml->othertext->d104; $publisher = (string)$xml->publisher->b081; $pricecover = (string)$xml->supplydetail->price->j151; $salesright = (string)$xml->salesrights->b090; @$productcode1 = htmlentities($productcode,ENT_QUOTES,''latin1_swedish_ci''); @$title1 = htmlentities($title,ENT_QUOTES,''latin1_swedish_ci''); @$author1 = htmlentities($author,ENT_QUOTES,''latin1_swedish_ci''); @$language1 = htmlentities($language,ENT_QUOTES,''latin1_swedish_ci''); @$category1 = htmlentities($category,ENT_QUOTES,''latin1_swedish_ci''); @$description1 = htmlentities($description,ENT_QUOTES,''latin1_swedish_ci''); @$publisher1 = htmlentities($publisher,ENT_QUOTES,''latin1_swedish_ci''); @$pricecover1 = htmlentities($pricecover,ENT_QUOTES,''latin1_swedish_ci''); @$salesright1 = htmlentities($salesright,ENT_QUOTES,''latin1_swedish_ci''); $conn = mysql_connect($dbhost, $dbuser, $dbpw); mysql_select_db($db); $sql = "INSERT INTO ebiblio VALUES (''" . $productcode1 . "'',''" . $title1 . "'',''" . $author1 . "'',''" . $language1 . "'',''" . $category1 . "'',''" . $description1 . "'',''" . $publisher1 . "'',''" . $pricecover1 . "'',''" . $salesright1 . "'')"; mysql_query($sql, $conn); $reader->next(''product''); } endwhile; ?>


La mayor parte de mi vida de análisis de XML se gasta extrayendo nuggets de información útil de camiones cargados de XML (Amazon MWS). Como tal, mi respuesta asume que solo quiere información específica y sabe dónde está ubicada.

Encuentro que la manera más fácil de usar XMLReader es saber de qué etiquetas quiero la información y usarlas. Si conoce la estructura del XML y tiene muchas etiquetas únicas, creo que usar el primer caso es fácil. Los casos 2 y 3 son solo para mostrarle cómo se puede hacer para etiquetas más complejas. Esto es extremadamente rápido; Tengo una discusión sobre la velocidad en ¿Cuál es el analizador XML más rápido en PHP?

Lo más importante que debe recordar al hacer un análisis basado en etiquetas como este es usar if ($myXML->nodeType == XMLReader::ELEMENT) {... - que comprueba para estar seguro de que solo estamos tratando con nodos de apertura y no espacio en blanco o nodos de cierre o lo que sea.

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(); }


La respuesta aceptada me dio un buen comienzo, pero trajo más clases y más procesamiento del que me hubiera gustado; entonces esta es mi interpretación:

$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();


Me temo que usar XmlReader :: expand () puede consumir mucha RAM cuando el subárbol no es tan pequeño. No estoy seguro de que sea una buena alternativa a XmlReader. Sin embargo, estoy de acuerdo en que XmlReader es muy débil y no es muy adecuado para procesar árboles XML anidados complejos. Realmente no me gustan dos cosas: en primer lugar, que el nodo actual no tiene su ruta en el árbol XML accesible como propiedad, y segundo que no se puede ejecutar el proceso XPath mientras se leen los nodos. Por supuesto, la consulta real de XPath consumirá mucho tiempo para XML grande, pero en su lugar podría utilizarse "path hooks", como cuando la ruta de elemento actual coincide con el subárbol (raíz) de una función / método PHP. Así que desarrollé mis propias clases encima de XmlReader hace algunos años. No son perfectos y tal vez escribiría mejor hoy, pero aún podría ser útil para alguien:

https://bitbucket.org/sdvpartnership/questpc-framework/src/c481a8b051dbba0a6644ab8a77a71e58119e7441/includes/Xml/Reader/?at=master

Construyo la ruta XML ''node1 / node2'' y luego utilizo ganchos con coincidencias PCRE que son menos potentes que XPath, pero fueron suficientes para mis necesidades. Procesé XML grande bastante complejo con estas clases.


Para xml formateado con atributos ...

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>

código 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();


Todo depende de cuán grande sea la unidad de trabajo, pero supongo que estás intentando tratar cada nodo <product/> en sucesión.

Para eso, la forma más simple sería usar XMLReader para llegar a cada nodo, luego usar SimpleXML para acceder a ellos. De esta forma, mantiene bajo el uso de memoria porque está tratando un nodo a la vez y aún aprovecha la facilidad de uso de SimpleXML. Por ejemplo:

$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''); }

Descripción rápida de los pros y los contras de diferentes enfoques:

Sólo XMLReader

  • Pros: rápido, usa poca memoria

  • Contras: excesivamente difícil de escribir y depurar, requiere mucho código de usuario para hacer algo útil. El código de usuario es lento y propenso a errores. Además, te deja con más líneas de código para mantener

XMLReader + SimpleXML

  • Pros: no usa mucha memoria (solo la memoria necesaria para procesar un nodo) y SimpleXML es, como su nombre lo indica, realmente fácil de usar.

  • Contras: crear un objeto SimpleXMLElement para cada nodo no es muy rápido. Realmente debe compararlo para saber si es un problema para usted. Sin embargo, incluso una máquina modesta podría procesar mil nodos por segundo.

XMLReader + DOM

  • Pros: utiliza casi tanta memoria como SimpleXML y XMLReader::expand() es más rápido que la creación de un nuevo SimpleXMLElement. Ojalá fuera posible usar simplexml_import_dom() pero parece que no funciona en ese caso

  • Contras: DOM es molesto para trabajar. Está a medio camino entre XMLReader y SimpleXML. No es tan complicado e incómodo como XMLReader, pero está a años luz de trabajar con SimpleXML.

Mi consejo: escribe un prototipo con SimpleXML, mira si funciona para ti. Si el rendimiento es primordial, prueba DOM. Manténgase lo más lejos posible de XMLReader. Recuerde que mientras más código escriba, mayor será la posibilidad de que introduzca errores o introduzca regresiones de rendimiento.


XMLReader está bien documentado en el sitio PHP . Este es un analizador XML Pull, lo que significa que se usa para iterar a través de nodos (o nodos DOM) de un documento XML dado. Por ejemplo, podría revisar todo el documento que dio así:

<?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(); ?>

Depende de usted decidir cómo tratar con el nodo devuelto por XMLReader::expand() .


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)); } }