Programmation PHP/Exemples/DomXml
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- É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- É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
modifierOn 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 :
- si le premier enfant existe,
- on test le type de nœud,
- 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
modifierOn é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
modifierDans 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);
?>
Aperçu
modifierOn 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
modifierOn a une fonction fort utile à porter sur php5 ou à optimiser histoire de ne plus avoir d'incréments dans les données du tableau.