Pregunta

Tengo el siguiente archivo XML, el archivo es bastante grande y no he podido conseguir simplexml para abrir y leer el archivo, así que estoy tratando 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>

He lamentablemente no encontré un buen tutorial sobre esto para PHP y me gustaría ver cómo puedo obtener cada elemento de contenido para almacenar en una base de datos.

¿Fue útil?

Solución

Todo depende del tamaño de la unidad de trabajo, pero supongo que está tratando de tratar a cada nodos <product/> en la serie.

Por eso, la forma más sencilla sería utilizar XMLReader para llegar a cada nodo, a continuación, utilizar SimpleXML para acceder a ellos. De esta manera, se mantiene la baja utilización de la memoria, porque se está tratando un nodo a la vez y todavía aprovechar 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');
}

Breve resumen de los pros y los contras de diferentes enfoques:

XMLReader única

  • Pros: rápido, utiliza poca memoria

  • Contras: excesivamente duros para escribir y depurar, requiere porciones de código de espacio de usuario a hacer nada útil. código de espacio de usuario es lento y propenso a errores. Además, le deja con más líneas de código para mantener

XMLReader + SimpleXML

  • Pros:. No utiliza mucha memoria (sólo la memoria necesaria para procesar un nodo) y SimpleXML es, como su nombre lo indica, muy fácil de usar

  • Contras: crear un objeto SimpleXMLElement para cada nodo no es muy rápido. Usted realmente tiene que referencia para entender si se trata de un problema para usted. Incluso una máquina modesta sería capaz de procesar miles de nodos por segundo, sin embargo.

XMLReader + DOM

  • Pros: utiliza alrededor tanta memoria como SimpleXML y XMLReader: : ampliar () es más rápido que la creación de un nuevo SimpleXMLElement. Me gustaría que fuera posible utilizar simplexml_import_dom() pero no parece funcionar en este caso

  • Contras: DOM es molesto para trabajar con ellos. Está a medio camino entre XMLReader y SimpleXML. No es tan complicadas y difíciles como XMLReader, pero años luz de distancia de trabajo con SimpleXML.

Mi consejo: escribir un prototipo con SimpleXML, ver si funciona para usted. Si el rendimiento es de suma importancia, trate de DOM. Mantenerse lo más lejos posible XMLReader. Recuerde que cuanto más código que escriba, mayor será la posibilidad de que la introducción de insectos o la introducción de regresiones de rendimiento.

Otros consejos

Para XML formateado con los 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();

La mayor parte de mi vida XML análisis se gasta la extracción de pepitas de la información útil de camiones de XML (Amazon MWS). Como tal, mi respuesta supone que desea información específica única y usted sabe dónde se encuentra.

Me parece la forma más fácil de usar XMLReader es saber qué etiquetas Quiero que la información de y utilizarlos. Si conoce la estructura del XML y tiene un montón de etiquetas únicas, me parece que el uso del primer caso es el fácil. Los casos 2 y 3 son sólo para mostrar cómo se puede hacer para las etiquetas más complejas. Esto es extremadamente rápido; Tengo una discusión de velocidad sobre el ¿Cuál es el más rápido analizador XML en PHP?

Lo más importante para recordar al hacer el análisis sintáctico basado en etiquetas como esto es utilizar if ($myXML->nodeType == XMLReader::ELEMENT) {... -. Que comprueba para asegurarse de que sólo estamos tratando con la apertura de los nodos y no un espacio en blanco o el cierre de los nodos 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 de lo que hubiera querido; así que 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();

XMLReader está bien documentada en la sitio PHP . Este es un analizador de tracción XML, lo que significa que utiliza para iterar a través de nodos (o DOM nodos) de documento XML dado. Por ejemplo, usted podría ir a través de todo el documento que dio como esto:

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

Es entonces depende de usted para 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));
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top