web-dev-qa-db-fra.com

Comment utiliser XMLReader en PHP?

J'ai le fichier XML suivant, le fichier est plutôt volumineux et je n'ai pas réussi à obtenir simplexml pour l'ouvrir et le lire; j'essaie donc XMLReader sans succès 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>

Malheureusement, je n'ai pas trouvé de bon tutoriel sur ceci pour PHP et j'aimerais voir comment je peux obtenir le contenu de chaque élément dans une base de données.

74
Shadi Almosri

Tout dépend de la taille de l'unité de travail, mais j'imagine que vous essayez de traiter chaque nœud <product/> Successivement.

Pour cela, le moyen le plus simple serait d'utiliser XMLReader pour accéder à chaque nœud, puis d'utiliser SimpleXML pour y accéder. Ainsi, vous réduisez l'utilisation de la mémoire, car vous ne traitez qu'un seul nœud à la fois et vous exploitez toujours la simplicité d'utilisation de SimpleXML. Par exemple:

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

Aperçu rapide des avantages et des inconvénients des différentes approches:

XMLReader uniquement

  • Avantages: rapide, utilise peu de mémoire

  • Inconvénients: excessivement difficile à écrire et à déboguer, nécessite beaucoup de code utilisateur pour accomplir quoi que ce soit d’utile. Le code Userland est lent et sujet aux erreurs. De plus, cela vous laisse plus de lignes de code à maintenir

XMLReader + SimpleXML

  • Avantages: n'utilise pas beaucoup de mémoire (seulement la mémoire nécessaire pour traiter un nœud) et SimpleXML est, comme son nom l'indique, très facile à utiliser.

  • Inconvénients: la création d'un objet SimpleXMLElement pour chaque nœud n'est pas très rapide. Vous devez vraiment le comparer pour comprendre si c'est un problème pour vous. Même une machine modeste serait capable de traiter un millier de nœuds par seconde.

XMLReader + DOM

  • Avantages: utilise environ autant de mémoire que SimpleXML et XMLReader :: expand () est plus rapide que la création d'un nouveau SimpleXMLElement. Je souhaite qu'il soit possible d'utiliser simplexml_import_dom() mais cela ne semble pas fonctionner dans ce cas

  • Inconvénients: DOM est agaçant de travailler avec. C'est à mi-chemin entre XMLReader et SimpleXML. Pas aussi compliqué et maladroit que XMLReader, mais à des années-lumière du travail avec SimpleXML.

Mon conseil: écrivez un prototype avec SimpleXML, voyez si cela fonctionne pour vous. Si les performances sont primordiales, essayez DOM. Restez aussi loin que possible de XMLReader. N'oubliez pas que plus vous écrivez de code, plus vous risquez d'introduire des bogues ou des régressions de performances.

211
Josh Davis

Pour XML formaté avec des attributs ...

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>

code 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();
9
try5tan3

La majeure partie de ma vie en analyse XML est consacrée à l'extraction de nuggets d'informations utiles à partir de chargements de XML (Amazon MWS). En tant que tel, ma réponse suppose que vous ne voulez que des informations spécifiques et que vous savez où elles se trouvent.

Je trouve que le moyen le plus simple d'utiliser XMLReader est de savoir quelles balises je souhaite utiliser et de les utiliser. Si vous connaissez la structure du fichier XML et que celui-ci comporte de nombreuses balises uniques, j’aperçois que l’utilisation du premier cas est simple. Les cas 2 et 3 sont simplement destinés à vous montrer comment faire pour des tags plus complexes. C'est extrêmement rapide. J'ai une discussion de la vitesse sur Quel est l'analyseur XML le plus rapide en PHP?

La chose la plus importante à retenir lors de l'analyse syntaxique basée sur les balises est d'utiliser if ($myXML->nodeType == XMLReader::ELEMENT) {... - qui vérifie que nous ne traitons que des nœuds en ouverture et non des espaces ou des nœuds en fermeture.

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

La réponse acceptée m'a donné un bon départ, mais elle a amené plus de cours et plus de traitement que je l'aurais souhaité. c'est donc mon interprétation:

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

XMLReader est bien documenté sur site PHP . Il s'agit d'un analyseur XML Pull, ce qui signifie qu'il est utilisé pour parcourir les nœuds (ou nœuds DOM) d'un document XML donné. Par exemple, vous pouvez parcourir tout le document que vous avez donné comme ceci:

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

Il vous appartient ensuite de décider comment traiter le noeud renvoyé par XMLReader :: expand () .

2
Percutio
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));
    }
}
2
sebob