Programmation PHP/Exemples/DomXml

Un livre de Wikilivres.
Aller à : navigation, rechercher



Les documents au format XML ont des imbrications parfois complexes et il n'est pas rare de devoir avoir recours à plusieurs fonctions pour faire le travail de décapsulation du contenu.

À travers cet exemple pratique nous écrirons une fonction pour convertir tout document XML en tableau suivant l'approche du web2 qui tient en deux tags très galvaudés [meta] et [data].

Objectif[modifier | modifier le wikicode]

  • Élaborer une fonction permettant de convertir en tableaux tout XML bien formé.
  • Créer une classe utilitaire domxml pour la recevoir avec ses petites sœurs.

Écriture d'un xml complexe[modifier | modifier le wikicode]

  • Écriture d'un document XML valide à imbrications multiples d'éléments hétéroclites comportant des attributs ou non...
 ?xml version="1.0" encoding="UTF-8"? 
 root 
   tag1 m1="attTag1" m2="att2" 
     sous-tag1 texte sous-tag1
       sous-tag2  /sous-tag2 
      texte tag1
     /sous-tag1 
   /tag1 
   tag1 
     sous-tag1 texte sous-tag1
       sous-tag2 att1="att2" att3="att3"  /sous-tag2 
     /sous-tag1 
     tag3 
       sous-tag1 texte sous-tag1
         sous-tag2 att1="attribut1"  /sous-tag2 
       /sous-tag1 
       etEncoreUnTagSuperflu 
         sous-tag1 texte sous-tag1
           sous-tag2 test /sous-tag2 
         /sous-tag1 
         tag1 
           p  b  sous-tag1 texte sous-tag1
             sous-tag2 att1="attribut1" /  /b 
           /sous-tag1 
          ceci /p est du body texte à extraire
         /tag1 
       /etEncoreUnTagSuperflu 
      text de début ou de fin
     /tag3 
   /tag1 
   tagNfo id="1" description="description" texteDescription /tagNfo 
 /root 
  • Sauvegarde de ce document.xml bien formé dans le même répertoire.

Création de la fonction[modifier | modifier le wikicode]

On doit maintenant écrire une fonction, la plus optimale possible, pour charger document.xml dans un tableau...

Cette fonction doit :

  • recevoir en entrée un flux xml/rss valide
  • doit migrer les attributs et le contenu dans un tableau

On écrit la fonction récursive qui décapsulera chaque tag en deux sous-tableaux par tag ([meta] ou attributs ) et ([data] ou nœud texte)

Cette fonction doit :

  • tester le type de nœud (texte ou tag)
  •  ? si tag extraire tous ses attributs dans [meta]
  •  ? si texte extraire le texte dans [data]
  • comme la structure est imbriquée et non listée :
    • les tags de débuts et de fins ne se suivent pas...
    • la fonction sera donc récursive et s'appellera elle-même pour un output lifo. Elle devra donc se passer son propre résultat en paramètre
    • par soucis du détail technique on fera une fonction getAttribute() pour optimiser le code
   function getAttribute($node)
   {//  ((dom)node) ((array)tab) 

     $tab=array();
     foreach($node- attributes() as $k1- $v1)
     {
	$tab[$k1- {''}- name]=$k1- {''}- value;
     }

   return $tab;
   }//

Description :

  • Pour chaque attribut, on place le contenu à une clé du tableau tab à retourner.

On s'attaque ensuite au plus gros du travail de notre convertisseur à savoir domxml2array() :

  function domxml2array($node,&$tab,&$i)
  {//  ((dom)node, (array)tab, (int)i) ((array)tab) 
  
    if($next=$node- first_child())        #1
    {
      do
      {
	switch($next- node_type()) #2
        {
	 case 3:
	 $tab['data']=$next- node_value();
	 break;
          case 1:
	 $tab[$next- node_name()."#".++$i]['meta'] = $this- getAttribute($next);
	 $this- domxml2array($next,$tab[$next- node_name()."#".$i],$i);
	 break;
        }
      }while($next=$next- next_sibling()); #3
    }
  return $tab;
  }//

Description :

  1. si le premier enfant existe
  2. on test le type de nœud
  3. on passe au nœud suivant

La fonction utilitaire print_r_html disponible sur php.net permettra de déposer le contenu à l'écran :

function print_r_html($data,$return_data=false)
{
    $data = print_r($data,true);
    $data = str_replace( " "," ", $data);
    $data = str_replace( "\r\n"," br/ \r\n", $data);
    $data = str_replace( "\r"," br/ \r", $data);
    $data = str_replace( "\n"," br/ \n", $data);

    if (!$return_data)
        echo $data;
    else
        return $data;
}

Création de la classe[modifier | modifier le wikicode]

On élabore une classe utilitaire pour php4 à implémenter au fur et à mesure :

  • On la baptise DomTree.
  • On y implémente les fonctions créées...
  • On sauvegarde la classe dans DomTree.Class.php.
 ?php

Class DomTree
{

#init
  
  var $tab = array();
  var $domNode;

#constructor 

  function DomTree($xml,$type)
  {//  ((string)xml,(int)type) ((dom)node) 
  
    if(!$type)
    {
      $this- domNode = domxml_open_file($xml);
    } else {
      $this- domNode = domxml_open_mem($xml);
    }
  }

#get 

  function getTag($tag)
  {//  ((string)tag) ((dom)node) 
			
  return $this- domNode- get_elements_by_tagname($tag);
  }//

  function getAttribute($node)
  {//  ((dom)node) ((dom)node) 

    $tab=array();
    foreach($node- attributes() as $k1- $v1)
    {
      $tab[$k1- {''}- name]=$k1- {''}- value;
    }

  return $tab;
  }//

#set

#spec

  function domxml2array($node,&$tab,&$i)
  {//  ((dom)node, (array)tab, (int)i) ((array)tab) 
  
    if($next=$node- first_child())
    {
      do
      {
	switch($next- node_type()) 
        {
	 case 3:
	 $tab['data']=$next- node_value(); 
	 break;
          case 1:
	 $tab[$next- node_name()."#".++$i]['meta'] = $this- getAttribute($next);
	 $this- domxml2array($next,$tab[$next- node_name()."#".$i],$i);
	 break;
        }
      }while($next=$next- next_sibling());
    }
  return $this- tab=$tab;
  }//

}

? 

Application[modifier | modifier le wikicode]

Dans un fichier test.php on instancie la classe et on l'exécute:

 ?php

  header("Cache-Control: no-cache, must-revalidate");
  header("Content-Type: text/html");
  
  // appel de la classe
  require_once"DomTree.class.php";

  // création de l'objet
  $doc  = new DomTree('document.xml');

  // sélection du noeud
  $root = $doc- getTag('root');
  
  // conversion du noeud root en tableau
  $tab = $doc- domxml2array($root[0]);

  // affichage du tableau
  print_r_html($tab);

? 

Aperçu[modifier | modifier le wikicode]

On obtient un arbre structuré easy2use pour le web2

Array
(
    [tag1#1] =  Array
        (
            [meta] =  Array
                (
                    [m1] =  attTag1
                    [m2] =  att2
                )

            [sous-tag1#2] =  Array
                (
                    [meta] =  Array
                        (
                        )

                    [data] =  texte tag1
                    [sous-tag2#3] =  Array
                        (
                            [meta] =  Array
                                (
                                )

                        )

                )

            [data] =  
 
        )

    [data] =  
 
    [tag1#4] =  Array
        (
            [meta] =  Array
                (
                )

            [sous-tag1#5] =  Array
                (
                    [meta] =  Array
                        (
                        )

                    [data] =  texte sous-tag1
                    [sous-tag2#6] =  Array
                        (
                            [meta] =  Array
                                (
                                    [att1] =  att2
                                    [att3] =  att3
                                )

                        )

                )

            [data] =  
 
            [tag3#7] =  Array
                (
                    [meta] =  Array
                        (
                        )

                    [sous-tag1#8] =  Array
                        (
                            [meta] =  Array
                                (
                                )

                            [data] =  texte sous-tag1
                            [sous-tag2#9] =  Array
                                (
                                    [meta] =  Array
                                        (
                                        )

                                )

                        )

                    [data] =  
   text de début ou de fin
   
                    [etEncoreUnTagSuperflu#10] =  Array
                        (
                            [meta] =  Array
                                (
                                )

                            [sous-tag1#11] =  Array
                                (
                                    [meta] =  Array
                                        (
                                        )

                                    [data] =  texte sous-tag1
                                    [sous-tag2#12] =  Array
                                        (
                                            [meta] =  Array
                                                (
                                                )

                                            [data] =  test
                                        )

                                )

                            [data] =  
     
                            [tag1#13] =  Array
                                (
                                    [meta] =  Array
                                        (
                                        )

                                    [p#14] =  Array
                                        (
                                            [meta] =  Array
                                                (
                                                )

                                            [b#15] =  Array
                                                (
                                                    [meta] =  Array
                                                        (
                                                        )

                                                    [sous-tag1#16] =  Array
                                                        (
                                                            [meta] =  Array
                                                                (
                                                                )

                                                            [data] =  texte sous-tag1
                                                            [sous-tag2#17] =  Array
                                                                (
                                                                    [meta] =  Array
                                                                        (
                                                                            [att1] =  attribut1
                                                                        )

                                                                )

                                                        )

                                                )

                                            [data] =  
         ceci
                                        )

                                    [data] =  est du body texte à extraire
       
                                )

                        )

                )

        )

    [tagNfo#18] =  Array
        (
            [meta] =  Array
                (
                    [id] =  1
                    [description] =  description
                )

            [data] =  texteDescription
        )

)

En bref[modifier | modifier le wikicode]

On a une fonction fort utile à porter sur php5 ou à optimiser histoire de ne plus avoir d'incréments dans les données du tableau.