Recherche de balises
Il est aussi possible de faire des recherches sur tout le
document XML, pour obtenir le contenu des balises portant
un certain nom. Dans certaines situations où les balises
sont dispersées dans tout le document, c'est une fonction
précieuse pour les rassembler. La méthode xpath()
se charge alors d'analyser l'arbre et de retourner un tableau
d'éléments SimpleXML.
<?php
$string = <<<XML
<a>
<b>
<c>autre texte</c>
<c>
<d>texte</d>
<d>texte2</d>
</c>
<c>
<d>texte3</d>
<d>texte4</d>
</c>
</b>
<d id= '33'>
<c>contenu</c>
</d>
</a>
XML;
$xml = simplexml_load_string($string);
/* On cherche les balises d */
$result = $xml->xpath('//d');
print_r($result);
?>
Par
rapport à l'exemple précédent, vous pouvez remarquer les
deux anti-slash qui débutent la recherche. On indique ici
au moteur XPath que l'on recherche les balises D, et non
pas qu'on veut traiter une sous-partie de l'arborescence.
Pour rechercher plusieurs balises différentes, vous pouvez
les séparer par un seul anti-slash, comme ceci :
//d/c/a
Gestion des espaces de noms
SimpleXML supporte les espaces de noms de manière très simple.
La notation
$balise_mere->$balise_fille
ne peut pas être utilisée avec les espaces de noms, car
il faudrait un moyen de les configurer : cela éloignerait
SimpleXML de son objectif de simplicité. A la place, les
concepteurs de l'extension proposent de passer un argument
optionnel aux méthodes
children()
et
attributes(). Voyons
comment cela se passe.
Dans le cadre de notre article, nous allons utiliser un
fichier RSS disponible sur nexen.net, et qui contient l'actualité
PHP et MySQL du jour. Voici son adresse : http://www.nexen.net/news/backend.1.rss
Voici un extrait du contenu :
<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- generator="FeedCreator 1.6" -->
<rdf:RDF
xmlns="http://purl.org/rss/1.0/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel rdf:about="http://www.nexen.net/news/backend.1.rss">
<title>PHP news</title>
<description>Actualit Nexen.net
: PHP & MySQL</description>
<link>http://www.nexen.net/news/</link>
<image rdf:resource="http://goodies.nexen.net/img/logo_88x31.gif"
/>
<dc:date>2004-08-10T18:41:19+00:00</dc:date>
<items>
<rdf:Seq>
<rdf:li
rdf: resource="http://www.nexen.net/news/
gen.php/2004/08/10/3331,0,0,0,0.php" />
<rdf:li
rdf:resource="http://www.nexen.net/news/
gen.php/2004/08/10/3330,0,0,0,0.php"/>
<rdf:li
rdf:resource="http://www.nexen.net/news/
gen.php/2004/08/10/3329,0,0,0,0.php"/>
<rdf:li
rdf:resource="http://www.nexen.net/news/
gen.php/2004/08/10/3328,0,0,0,0.php"/>
</rdf:Seq>
</items>
</channel>
<image rdf:about="http://goodies.nexen.net/img/logo_88x31.gif">
<title>nexen.net</title>
<link>http://www.nexen.net</link>
<url>http://goodies.nexen.net/img/logo_88x31.gif</url>
</image>
<item rdf:about="http://www.nexen.net/news/
gen.php/2004/08/10/3331,0,0,0,0.php">
<dc:format>text/html</dc:format>
<dc:date>2004-08-10T17:36:36+00:00</dc:date>
<title>"echo"
: lapin ou tortue ?</title>
<link>http://www.nexen.net/news/
gen.php/2004/08/10/3331,0,0,0,0.php</link>
<description>Cet article fait
le point sur les performances de "echo"
lorsque l'on utilise la concaténation ou les paramètres
multiples.</description>
</item>
</rdf>
On remarque dès le début du fil de dépêches la présence
de trois espaces de noms, spécifiés dans la balise RDF initiale.
Par exemple,
xmlns:dc="http://purl.org/dc/elements/1.1/"
indique que l'espace de nom dc repose sur des spécifications
définies par l'URL indiquée. Dans le corps de notre fil
de dépêches, nous retrouvons des balises de cette forme
:
<dc:date>. Cette balise
fait partie de l'espace de noms
dc.
Les balises qui ne sont pas préfixées par un espace de noms
font alors partie de l'espace de noms global.
Pour accéder aux balises disponibles dans la balise
channel,
on utilise le code suivant :
<?php
$rss = simplexml_load_file('http://www.nexen.net/news/backend.1.rss');
foreach ($rss->channel as $c) {
foreach ($c->children() as $tag => $item) {
printf("balise : %s\n", $tag);
}
}
?>
Le script affiche :
Balise : title
Balise : description
Balise : link
Balise : image
Balise : items
En observant de plus près, nous nous apercevons qu'il manque
la balise
date. Cette dernière
fait partie de l'espace de nom
dc,
puisqu'elle est précédée par
dc:.
Pour y accéder, il nous faut préciser aussi cet espace de
nom. L'exemple précédent devient :
<?php
$rss = simplexml_load_file('http://www.nexen.net/news/backend.1.rss');
foreach ($rss->channel as $c) {
foreach ($c->children('http://purl.org/dc/elements/1.1/')
as $tag => $item) {
printf("Balise : %s\n", $tag);
}
}
?>
Balise : date
Théoriquement, nous pourrions utiliser aussi le nom 'dc'
pour sélectionner les balises de
channel
qui font partie de l'espace de noms 'http://purl.org/dc/elements/1.1/'.
Toutefois, il semble que cette fonctionnalité ne soit pas
totalement implémentée, et nous n'avons pas pu la faire
fonctionner dans cet exemple. Peut-être cela sera-t-il corrigé
pour PHP 5.1 ?
L'utilisation des espaces de noms est identique pour les
attributs et la méthode
attributes()
:
<?php
$rss = simplexml_load_file('http://www.nexen.net/news/backend.1.rss');
foreach ($rss->channel as $c) {
foreach ($rss->channel->attributes('http://www.w3.org/1999/02/22-rdf-syntax-ns#')
as $tag => $item) {
printf("Attribut RDF : %s\n", $tag);
}
print $rss->channel['about']."\n";
}
?>
Attribut RDF : about
About
En précisant l'espace de nom
rdf,
nous avons obtenu les identifiants de cet espace.
Si nous souhaitons obtenir tous les identifiants, quel que
soit leur espace de nom, alors la notation
$balise['attribut']
est toujours disponible, et recense tous les identifiants.
De même, la notation
$balise->sous_balise
et
$balise->sous_balise[]
donne accès à toutes les balises détectées, indépendamment
de leur espace de noms. Le plus important est que l'ensemble
reste simple et souple à utiliser.