Aller au contenu

Programmation PHP/Exemples/DomXml

Un livre de Wikilivres.

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].

  • É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;
        }//

    }

    ?>

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 nœud
    $root = $doc->getTag('root');

    // conversion du nœud root en tableau
    $tab = $doc->domxml2array($root[0]);

    // affichage du tableau
    print_r_html($tab);

    ?>

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
        )

)

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.