Comment utiliser XMLReader en PHP?

j'ai le fichier XML suivant, le fichier est assez grand et je n'ai pas été en mesure d'obtenir simplexml pour ouvrir et lire le fichier donc j'essaie XMLReader avec aucun 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>

Je n'ai malheureusement pas trouvé un bon tutoriel sur ce sujet pour PHP et j'aimerais voir comment je peux obtenir chaque contenu d'élément à stocker dans une base de données.

68
demandé sur Benjamin 2009-12-02 22:17:27

7 réponses

tout dépend de la taille de l'Unité de travail, mais je suppose que vous essayez de traiter chaque <product/> noeuds dans la succession.

pour cela, la manière la plus simple serait D'utiliser XMLReader pour accéder à chaque noeud, puis D'utiliser SimpleXML pour y accéder. De cette façon, vous gardez l'utilisation de la mémoire faible parce que vous traitez un noeud à la fois et vous tirez toujours avantage de la facilité 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 de différentes approches:

XMLReader seulement

  • Avantages: rapide, utilise peu de mémoire

  • Cons: excessivement difficile à écrire et à déboguer, nécessite beaucoup de code userland pour faire quelque chose d'utile. Userland code est lent et sujet à l'erreur. De plus, il vous laisse avec plus de lignes de code pour maintenir

XMLReader + SimpleXML

  • Pros: n'utilise pas beaucoup de mémoire (seulement la mémoire nécessaire pour traiter un noeud) et SimpleXML est, comme son nom l'indique, vraiment facile à utiliser.

  • Cons: la création d'un objet SimpleXMLElement pour chaque noeud 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 noeuds par la deuxième, cependant.

XMLReader + DOM

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

  • contre: DOM est ennuyeux à travailler. C'est à mi-chemin entre XMLReader et SimpleXML. Pas aussi compliqué et embarrassant que XMLReader, mais à des années-lumière de travailler avec SimpleXML.

mon conseil: écrire un prototype avec SimpleXML, voir si cela fonctionne pour vous. Si la performance est primordiale, essayez DOM. Restez aussi loin que possible de XMLReader. Rappelez-vous que plus vous écrivez de code, plus vous avez la possibilité d'introduire des bugs ou des régressions de performance.

198
répondu Josh Davis 2009-12-03 10:36:34

pour xml formaté avec des attributs...

"151920920 des données".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();
8
répondu try5tan3 2015-08-06 19:13:46

la majeure partie de ma vie D'analyse XML est consacrée à extraire des fragments d'information utile à partir de chargements routiers de XML (Amazon MWS). Par conséquent, ma réponse suppose que vous voulez seulement des renseignements précis et que vous savez où ils se trouvent.

je trouve que la façon la plus simple d'utiliser XMLReader est de savoir sur quelles étiquettes je veux les informations et de les utiliser. Si vous connaissez la structure du XML et qu'il y a beaucoup d'étiquettes uniques, je trouve que l'utilisation du premier cas est la plus facile. Les cas 2 et 3 sont juste pour vous montrer comment il peut être fait pour les étiquettes plus complexes. C'est extrêmement rapide; j'ai une discussion de speed over sur Quel est L'analyseur XML le plus rapide en PHP?

la chose la plus importante à se rappeler en faisant l'analyse basée sur des balises comme ceci est d'utiliser if ($myXML->nodeType == XMLReader::ELEMENT) {... -qui vérifie pour être sûr que nous avons affaire uniquement à des noeuds d'ouverture et non à des noeuds d'espace ou de fermeture ou quoi que ce soit.

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();
}
5
répondu Josiah 2017-05-23 12:03:02

XMLReader est bien documenté sur PHP site . Il s'agit d'un analyseur de Pull XML, ce qui signifie qu'il est utilisé pour itérer à travers les noeuds (ou les noeuds DOM) d'un document XML donné. Par exemple, vous pourriez 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();
?>

c'est alors à vous de décider comment gérer le noeud retourné par XMLReader::expand () .

2
répondu JP. 2009-12-02 19:42:11
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
répondu sebob 2013-10-10 07:04:36

la réponse acceptée m'a donné un bon départ, mais a apporté plus de classes et plus de traitement que j'aurais voulu; 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();
2
répondu Francis Lewis 2014-06-20 06:07:37

ce sujet est abandonné depuis longtemps, mais je viens de le trouver. Grâce À Dieu.

mon problème est que je dois lire le fichier ONIX (données du livre), et le stocker dans notre base de données. J'utilise simplexml_load avant, et bien qu'il utilise beaucoup de mémoire, mais toujours ok pour un fichier relativement petit (jusqu'à 300 MO). Au-delà de cette taille est un désastre pour moi.

après lecture, en particulier L'interprétation de Francis Lewis, j'utilise la combinaison de xmlreader et simplexml. Le résultat est exceptionnelle, l'utilisation de la mémoire est petite et l'insérer dans la base de données assez rapidement pour moi.

Voici mon code:

<?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;
?>
2
répondu Ezra Kurniadi 2016-07-12 03:03:46