IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

XML/XSL et SOAP Discussion :

Parcours XML à plusieurs niveaux PHP Xmlreader SimpleXMLElement


Sujet :

XML/XSL et SOAP

  1. #1
    Membre averti
    Homme Profil pro
    Développeur Web
    Inscrit en
    Octobre 2012
    Messages
    48
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Octobre 2012
    Messages : 48
    Par défaut Parcours XML à plusieurs niveaux PHP Xmlreader SimpleXMLElement
    Bonjour,

    Je me tourne vers vous car j'ai un GROS problème dans l'analyse de fichier XML.

    J'utilise XmlReader via PHP avec SimpleXMLElement car les fichiers que j'analyse sont important (supérieur à 1gb).

    Jusqu'à maintenant l'analyse de flux ne me posait pas problème.

    Voici la méthode utilisée pour un flux classique en exemple, le noeud station uniquement m'intéresse. Dans cette méthode j'arrête au dernier noeud station :

    Flux XML simple sur un niveau
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <?xml version="1.0"?>
    <offres>
     <catalogue id="226"  site="france" >
     <stations>
       <station>
        <identifiant>
         <![CDATA[11]]>
        </identifiant>
        </station>
        <station>
        <identifiant>
         <![CDATA[12]]>
        </identifiant>
        </station>
        <station>
        <identifiant>
         <![CDATA[13]]>
        </identifiant>
        </station>
       </stations>
    </catalogue></offres>

    Code PHP permettant l'ouverture et l'analyse du fichier
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <?php
    $reader = new XMLReader();
    $reader->open('test.xml');
     
    $doc = new DOMDocument;
     
    while ($reader->read() && $reader->name !== 'station');
     
    while($reader->name === 'station')
    {
     $node = new SimpleXMLElement(utf8_encode(html_entity_decode($reader->readOuterXML())));	
     $station_cle = (trim($node->station_cle));
     echo "$station_cle<br/>";	
     $reader->next('station');
    }
    // Je m'arrete bien au dernier noeud station
    }
    ?>



    Je dois dorénavant analyser plusieurs noeuds catalogues à la suite comprenant chacun plusieurs noeuds stations.


    Le code XML exemple pour mieux comprendre donne ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    <?xml version="1.0"?>
    <offres>
     <catalogue id="226"  site="france" >
     <stations>
       <station>
        <identifiant>
         <![CDATA[11]]>
        </identifiant>
        </station>
        <station>
        <identifiant>
         <![CDATA[12]]>
        </identifiant>
        </station>
        <station>
        <identifiant>
         <![CDATA[13]]>
        </identifiant>
        </station>
       </stations>
    </catalogue>
    <catalogue id="227"  site="france" >
     <stations>
       <station>
        <identifiant>
         <![CDATA[11]]>
        </identifiant>
        </station>
        <station>
        <identifiant>
         <![CDATA[12]]>
        </identifiant>
        </station>
        <station>
        <identifiant>
         <![CDATA[13]]>
        </identifiant>
        </station>
       </stations>
    </catalogue>
    </offres>

    Mon problème : avec le code d'analyse ci-dessus je ne parviens pas à passer aux catalogues suivant je reste dans le premier catalogue.. mon action se termine au dernier noeud station

    Comment faire pour passer au second catalogue ?

    J'ai essayé d'imbriquer cette boucle mais impossible de passer dans le second catalogue.

    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <?php
    while ($reader->read() && $reader->name !== 'offres');
     
    while($reader->name === 'offres')
    {
        while ($reader->read() && $reader->name !== 'catalogue');
        while($reader->name === 'catalogue')
        {
     
            while ($reader->read() && $reader->name !== 'station');
            while($reader->name === 'station')
            {
              $node = new SimpleXMLElement(utf8_encode(html_entity_decode($reader->readOuterXML())));	 
              $reader->next('station');
            }
        $reader->next('catalogue');
        }
    }

    1. J'ai bien tenté un foreach ou un simple for en calculant le nombre d'élément du tableau mais ce nombre peut être très important.. le but est de charger au fur et à mesure sans consommer trop de mémoire..

    2. Le problème vient-il du fait que je me réfère à chaque fois à reader de base ? Faut-il créer un nouveau reader à la suite ? Comme par exemple $reader_catalogue puis $reader_station ?

    Merci d'avance pour votre aide !

    Gloire à celui qui trouvera

  2. #2
    Membre Expert Avatar de tsuji
    Inscrit en
    Octobre 2011
    Messages
    1 558
    Détails du profil
    Informations forums :
    Inscription : Octobre 2011
    Messages : 1 558
    Par défaut
    Logiquement plus simple et plus de clarté et le résultat comme attendu, quoiqu'il puisse être racourci peut-être un peu.
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    while ($reader->read()) {
        if (($reader->nodeType==XMLReader::ELEMENT) && ($reader->name=='catalogue')) {
            //faire quelque chose envers chaque catalogue si besoin
            while($reader->read()) {
                if (($reader->nodeType==XMLReader::ELEMENT) && ($reader->name=='station')) {
                    $node = new SimpleXMLElement(utf8_encode(html_entity_decode($reader->readOuterXML())));	
                    //$station_cle = (trim($node->station_cle));    //je ne sais pas quoi
                    $station_cle = (trim($node->identifiant));
                    echo "$station_cle<br/>";
                    //faire des choses avec $node si besoin
                }
            }
        }
    }

  3. #3
    Membre averti
    Homme Profil pro
    Développeur Web
    Inscrit en
    Octobre 2012
    Messages
    48
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Octobre 2012
    Messages : 48
    Par défaut
    Bonjour, merci pour le retour !!

    Je viens d'effectuer un premier test et à priori cela n'a pas fonctionné car je continuais d'utiliser next('station') du coup plantage et impossible de passer au catalogue suivant.

    J'ai retiré next('station'); comme dans ton exemple et cela semble fonctionner sur un petit fichier.. je vais lancer un test sur mon fichier supérieur à 1gb mais si ça marche maintenant...

    Je reviens tout l'heure pour valider si ça a fonctionné..

    Merci


  4. #4
    Membre averti
    Homme Profil pro
    Développeur Web
    Inscrit en
    Octobre 2012
    Messages
    48
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Octobre 2012
    Messages : 48
    Par défaut
    J'ai modifié mon code et celui-ci me semble déjà plus logique..

    Les noeuds qui m'intéresse sont uniquement station pour récupérer la ville, résidence pour récupérer les illustrations et produits pour créer mon annonce. Les autres noeuds ne m'intéresse donc pas.

    Voici mon nouveau code
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    <?php
    	if(file_exists("file.xml"))
    	{
    		// Lancement de la mise à jour si besoin
    		if($date_mise_a_jour_file==$date_du_jour)
    		{
     
    			#######################################################################
    			################# ANALYSE DU FICHIER ETAPE PAR ETAPE ##################
    			#######################################################################
     
    					// Utilisation de XML reader pour pemrettre une lecture en continue du fichier
    					$reader = new XMLReader();
    					$reader->open('file.xml');
     
    					$i=0;
    					while ($reader->read()) 
    					{
    						// On analyse uniquement les balises noeud ouvrantes <noeud> et non son double </noeud>
    						if($reader->nodeType==XMLReader::ELEMENT)
    						{
    							if($reader->name=="station_cle")
    							{
    								$station_cle = "";
    								$reader->read(); $reader->read();
    								$station_cle = mysql_real_escape_string(trim($reader->value));
    								// echo "station $station_cle <br/>";
    							}
     
    							if($reader->name=="theme_libelle")
    							{
    								$theme_libelle = "";
    								$reader->read(); $reader->read();
    								$theme_libelle = mysql_real_escape_string(trim($reader->value));
    								// echo "$theme_libelle<br/>";
    							}
     
    							if($reader->name=="ville")
    							{
    								$ville = "";
    								$reader->read(); $reader->read();
    								$ville = mysql_real_escape_string(ucfirst(strtolower(trim($reader->value))));
    								$ville_url = str_replace($a, $b, ($ville));
    								$ville_url = mb_strtolower(preg_replace(array('/[^a-zA-Z0-9 \'-]/', '/[ -\']+/', '/^-|-$/'),array('', '-', ''), $ville_url));
    								$ville_url = mysql_real_escape_string($ville_url);
    								// echo "$ville<br/>";
    							}
     
    							if($reader->name=="insee")
    							{
    								$code_postal = "";
    								$reader->read(); $reader->read();
    								$code_postal = mysql_real_escape_string(trim($reader->value));
    								// echo "$code_postal<br/>";
    							}
     
    							if($reader->name=="departement")
    							{
    								$departement = "";
    								$reader->read(); $reader->read();
    								$departement = mysql_real_escape_string(trim($reader->value));
    							}
     
    							if($reader->name=="residence_cle")
    							{
    								$residence_cle = "";
    								$reader->read(); $reader->read();
    								$residence_cle = mysql_real_escape_string(trim($reader->value));
    								// echo "$residence_cle<br/>";
    							}
     
    							if($reader->name=='produit')
    							{
    								$node = new SimpleXMLElement(utf8_encode(html_entity_decode($reader->readOuterXML()))); // Noeud de départ
    								//print_r($node);echo "<br/><br/><br/><br/><br/>";
    								unset($node->departs); // Noeud après suppression du noeud departs
    								//print_r($node);
     
    								$id_house = mysql_real_escape_string(trim($node->produit_cle));
    								// echo "<br/><br/><br/>$id_house<br/>";
    								// echo "$ville $residence_cle<br/>";
     
    								if(!empty($id_house))
    								{
    									$tab_node = $node->photos->photo;
    									$total_node = count($tab_node);
     
    									$i_node = 0;
    									$tab_img = "";
     
    									while($i_node<$total_node)
    									{
    										$photo = utf8_decode(trim($tab_node[$i_node]));
    										$tab_img .="$photo|";
    										$i_node++;
    									}
     
    									$tab_img = mysql_real_escape_string($tab_img);
    									// echo "$tab_img<br/>";
     
    									$produit_type_cle = mysql_real_escape_string(trim($node->produit_type_cle));
    									$nb_personnes = mysql_real_escape_string(trim($node->produit_nb_pax));
    									$url_affiliation = mysql_real_escape_string(utf8_decode(utf8_decode(trim($node->acces_direct_produit)))); 
     
    									$langue = mysql_real_escape_string(trim($node->langues->langue['value']));
     
    									$nom_location = mysql_real_escape_string(utf8_decode(utf8_decode(trim($node->langues->langue->produit_libelle)))); 
    									$produit_type_libelle = mysql_real_escape_string(utf8_decode(utf8_decode(trim($node->langues->langue->produit_type_libelle)))); 
    									$produit_description = mysql_real_escape_string(utf8_decode(utf8_decode(trim($node->langues->langue->produit_description)))); 
    									$produit_equipement = mysql_real_escape_string(utf8_decode(utf8_decode(trim($node->langues->langue->produit_equipement)))); 
     
    									// On vérifie si le produit est déjà enregistré dans la base
    									$selection_existant = mysql_query("SELECT * FROM annonce WHERE id_house='$id_house'");
    									$total_existant = mysql_num_rows($selection_existant);
     
    									// echo "existant $total_existant<br/>";
     
    									// Insertion d'une nouvelle annonce
    									if($total_existant=="0")
    									{
    										$insertion
    									}
    									// Mise à jour d'une annonce
    									else
    									{
    										$maj
     
    									}
    								}
    							unset($node);
    							}
    						} // Fin de lecture des noeud ouvert uniquement
    					} // Fin de while reader permettant la lecture du fichier complet
    		} // Fin de récupération par FTP de la date de mise à jour
    	} // Fin de file_exists sur le fichier XML souhaité

    Mon problème actuel, le fichier complet n'est pas lu complètement.. le fichier pèse 1,6gb.

    Y a t-il possibilité de créer un nouveau fichier XML à partir du premier en supprimant les noeuds qui ne m'intéresse pas pour diminuer à la base la taille du fichier ?

    Merci de votre aide.

  5. #5
    Membre Expert Avatar de tsuji
    Inscrit en
    Octobre 2011
    Messages
    1 558
    Détails du profil
    Informations forums :
    Inscription : Octobre 2011
    Messages : 1 558
    Par défaut
    D'abord, ceci: pourquoi faut-il read() deux fois pour sortir la valeur ->value?
    $station_cle = "";
    $reader->read(); $reader->read();
    $station_cle = mysql_real_escape_string(trim($reader->value));
    // echo "station $station_cle <br/>";
    Je m'en doute grandement sans voir le document xml.

    Et puis,
    Mon problème actuel, le fichier complet n'est pas lu complètement.. le fichier pèse 1,6gb.
    Si vous aviez le doute que le problème provenait de l'importance du document, méfiez vous. XMLReader doit être capable de le tirer même à un moment donné, vous passez à SimpleXML pour une sous-aborescence que sa taille n'est comparablement beaucoup moins que le document originel. Si ça eventuellement pose problème, vous pouvez toujours vous placer algorithmiquement dedans le cadre de XMLReader.

    La raison qu'il s'ârret quelque part doit être envisagée. Le document pouvait mal-formée pour des raisons multiples, etc. Pour faire voir, lire un peu sur la configuration track_errors dans php.ini. Il est par défaut off. Changez là on.
    Et puis dans le code, vous devriez controler la variable $php_errormsg quelque peu comme ça.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    if(isset($php_errormsg)) {
        echo "<div>error message: ", $php_errormsg,"</div>\n";
    }
    Faites voir si ça aide?

  6. #6
    Membre averti
    Homme Profil pro
    Développeur Web
    Inscrit en
    Octobre 2012
    Messages
    48
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Octobre 2012
    Messages : 48
    Par défaut
    Merci pour ton retour.

    Je n'ai pas pris le temps de répondre avant..

    Sujet résolu !!

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 2
    Dernier message: 08/05/2011, 00h23
  2. [Flex4] Dataprovider issu de XML à plusieurs niveaux de noeuds
    Par Imadus dans le forum Flex
    Réponses: 4
    Dernier message: 29/11/2010, 17h14
  3. Réponses: 3
    Dernier message: 20/08/2008, 10h24
  4. [JDOM] Fichier XML à plusieurs niveaux
    Par sidneyvba dans le forum Format d'échange (XML, JSON...)
    Réponses: 1
    Dernier message: 06/11/2007, 15h58
  5. Réponses: 3
    Dernier message: 30/08/2006, 16h39

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo