Le langage XML (eXtensible Markup Language (Langage à Balises
Extensible)) est un format structuré de données pour les
échanges sur le web. C'est un standard défini par le
consortium World Wide Web (W3C). Plus d'informations à propos
du XML et des technologies afférentes sont accessibles (en anglais)
http://www.w3.org/XML/.
Cette extension PHP implémente la bibliothèque expat
de James Clark sous PHP. Cela vous permettra d'analyser mais
pas de valider les documents XML. Ce langage supporte trois types de
jeux de caractères différents,
disponibles aussi sous PHP : US-ASCII, ISO-8859-1
et UTF-8. UTF-16 n'est pas supporté.
Cette extension vous permet de créer des
analyseurs XML
puis de définir des gestionnaires
pour chaque événement XML. Les analyseurs XML disposent
de quelques paramètres
que vous pouvez régler.
Cette extension PHP utilise expat compat layer
par défaut. Elle peut aussi utiliser expat, qui est
disponible sur http://www.jclark.com/xml/expat.html.
Le fichier Makefile livré avec expat
ne construit pas par défaut de bibliothèque : il faut utiliser
la ligne suivante :
Ces fonctions sont activées par défaut, et utilisent la
bibliothèque expat fournie avec la distribution. Vous pouvez
désactiver le support de XML en utilisant l'option de
compilation --disable-xml.
Si vous compilez PHP comme module pour Apache 1.3.9 ou supérieur,
PHP va automatiquement utiliser la bibliothèque
expat fournie par Apache. Si vous ne
souhaitez pas utiliser la bibliothèque expat intégrée,
il faut que vous compiliez PHP avec l'option
--with-expat-dir=DIR, où DIR est le
dossier d'installation de votre bibliothèque expat.
La version Windows de PHP
dispose du support automatique de cette extension. Vous n'avez pas à ajouter
de bibliothèque supplémentaire pour disposer de ces fonctions.
La ressource xml est retournée par
xml_parser_create() et
xml_parser_create_ns(), et représente
un analyseur XML Ã utiliser avec les autres fonctions de cette
extension.
Ces constantes sont définies par cette
extension, et ne sont disponibles que si cette extension a été compilée avec
PHP, ou bien chargée au moment de l'exécution.
Un événement est généré
à chaque fois que l'analyseur XML rencontre une balise de
début ou de fin. Deux gestionnaires sont disponibles : un
pour le début, et un pour la fin.
"Character data" correspond grosso modo à tout ce qui n'est
pas une balise XML, y compris les espaces entre les balises. Notez
bien que l'analyseur XML n'ajoute ou n'efface aucun espace, et que
c'est à l'application (c'est-à -dire vous) de
décider de la signification de ces espaces.
Les programmeurs PHP sont habitués aux instructions
exécutables (processing instructions ou PIs).
<?php ?> est une instruction exécutable où
php est appelé programme cible.
Ces instructions sont gérées de manière spécifique,
(sauf le programme cible "XML" qui est réservé).
Tout ce qui n'a pas trouvé de gestionnaire est transmis
au gestionnaire par défaut. Vous retrouverez par exemple,
les déclarations de type de document dans ce gestionnaire.
Ce gestionnaire est appelé lorsque l'analyseur XML trouve une
référence à une entité générale externe. Cela peut être une
référence à un fichier ou à une URL. Reportez-vous Ã
entité externe
pour un exemple.
Les fonctions de gestion des balises peuvent rencontrer des balises en
minuscule, majuscule ou encore dans un mélange des deux. En XML,
la procédure standard est d'"identifier les séquences de
caractères qui ne sont pas reconnues comme majuscule, et de les
remplacer par leur équivalent majuscule". En d'autres termes,
XML met toutes les lettres en majuscules.
Par défaut, tous les noms des éléments qui sont
transmis aux fonctions de gestion sont mises en majuscule. Ce
comportement est contrôlé par l'analyseur XML, et
peut être lu et modifié avec les fonctions respectives
xml_parser_get_option() et
xml_parser_set_option().
L'extension XML de PHP supporte les caractères
Unicode grâce Ã
différents codages. Il y a deux types de codages de
caractères : le codage à la source et le
codage à la cible. PHP utilise le
UTF-8 comme représentation interne.
L'encodage à la source est effectué lors de
l'analyse du fichier par XML.
Lors de la création
d'un analyseur XML), un type de codage à la
source peut être spécifié (et il ne pourra plus
être modifié jusqu'Ã la destruction de
l'analyseur). Les codages supportés sont :
ISO-8859-1, US-ASCII et
UTF-8. Les deux derniers sont des codages
à un seul octet, c'est-à -dire que les caractères
sont représentés sur un seul octet. UTF-8
peut représenter des caractères composés par un
nombre variable de bits (jusqu'Ã 21), allant de 1 Ã
quatre octets. Le codage par défaut utilisé par PHP
ISO-8859-1.
Le codage à la cible est effectué lorsque PHP transfert
les données aux gestionnaires XML. Lorsqu'un analyseur est
créé, le codage à la cible est spécifié
de la même façon que le codage à la source, mais
il peut être modifié Ã tout moment. Le codage
à la cible affectera les balises, tout comme les
données brutes, et les noms des instructions exécutables.
Si l'analyseur XML rencontre un caractère qu'il ne
connaît pas (hors limite, par exemple), il retournera une erreur.
Si PHP rencontre un caractère dans le document XML analysé,
qu'il ne peut pas représenter dans le codage à la cible
choisi, le caractère sera remplacé par un point
d'interrogation (cette attitude est susceptible de changer
ultérieurement).
Ce premier exemple affiche la structure de l'élément
de début dans un document avec indentation.
Exemple 1. Afficher une structure XML
<?php $file = "donnees.xml"; $depth = array();
function debutElement($parser, $name, $attrs) { global $depth; for ($i = 0; $i < $depth[$parser]; $i++) { echo " "; } echo "$name\n"; $depth[$parser]++; }
function finElement($parser, $name) { global $depth; $depth[$parser]--; }
$xml_parser = xml_parser_create(); xml_set_element_handler($xml_parser, "debutElement", "finElement"); if (!($fp = fopen($file, "r"))) { die("Impossible d'ouvrir le fichier XML"); }
while ($data = fread($fp, 4096)) { if (!xml_parse($xml_parser, $data, feof($fp))) { die(sprintf("erreur XML : %s à la ligne %d", xml_error_string(xml_get_error_code($xml_parser)), xml_get_current_line_number($xml_parser))); } } xml_parser_free($xml_parser); ?>
Cet exemple remplace les balises XML d'un document par des balises
HTML. Les éléments inconnus seront ignorés.
Bien entendu, cet exemple sera appliqué Ã un type
précis de fichiers XML.
function startElement($parser, $name, $attrs) { global $map_array; if (isset($map_array[$name])) { echo "<$map_array[$name]>"; } }
function endElement($parser, $name) { global $map_array; if (isset($map_array[$name])) { echo "</$map_array[$name]>"; } }
function characterData($parser, $data) { echo $data; }
$xml_parser = xml_parser_create(); // Utilisons la gestion de casse, de manière à être sûrs de trouver la balise dans $map_array xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, true); xml_set_element_handler($xml_parser, "startElement", "endElement"); xml_set_character_data_handler($xml_parser, "characterData"); if (!($fp = fopen($file, "r"))) { die("Impossible de trouver le fichier XML"); }
while ($data = fread($fp, 4096)) { if (!xml_parse($xml_parser, $data, feof($fp))) { die(sprintf("erreur XML : %s à la ligne %d", xml_error_string(xml_get_error_code($xml_parser)), xml_get_current_line_number($xml_parser))); } } xml_parser_free($xml_parser); ?>
Cet exemple exploite les références externes de XML :
il est possible d'utiliser un gestionnaire d'entité externe
pour inclure et analyser les documents, tous comme les instructions
exécutables peuvent servir à inclure et analyser
d'autres documents, et aussi fournir une indication de confiance
(voir plus bas).
Le document XML qui est utilisé dans cet exemple est fourni plus
loin dans l'exemple (xmltest.xml et
xmltest2.xml).
Exemple 3. Entité externe
<?php $file = "xmltest.xml";
function trustedFile($file) { // faites seulement confiance aux fichiers locaux dont vous êtes le propriétaire if (!eregi("^([a-z]+)://", $file) && fileowner($file) == getmyuid()) { return true; } return false; }
function startElement($parser, $name, $attribs) { echo "<<font color=\"#0000cc\">$name</font>"; if (count($attribs)) { foreach ($attribs as $k => $v) { echo " <font color=\"#009900\">$k</font>=\"<font color=\"#990000\">$v</font>\""; } } echo ">"; }
function endElement($parser, $name) { echo "</<font color=\"#0000cc\">$name</font>>"; }
function characterData($parser, $data) { echo "<strong>$data</strong>"; }
function PIHandler($parser, $target, $data) { switch (strtolower($target)) { case "php": global $parser_file; // si le document analysé est de confiance, nous déclarons qu'il est sûr // d'exécuter le code PHP qu'il contient. Si ce n'est pas le cas, le code est affiché // à la place. if (trustedFile($parser_file[$parser])) { eval($data); } else { printf("Untrusted PHP code: <em>%s</em>", htmlspecialchars($data)); } break; } }
function externalEntityRefHandler($parser, $openEntityNames, $base, $systemId, $publicId) { if ($systemId) { if (!list($parser, $fp) = new_xml_parser($systemId)) { printf("Could not open entity %s at %s\n", $openEntityNames, $systemId); return false; } while ($data = fread($fp, 4096)) { if (!xml_parse($parser, $data, feof($fp))) { printf("erreur XML : %s à la ligne %d lors de l'analyse de l'entité %s\n", xml_error_string(xml_get_error_code($parser)), xml_get_current_line_number($parser), $openEntityNames); xml_parser_free($parser); return false; } } xml_parser_free($parser); return true; } return false; }
function new_xml_parser($file) { global $parser_file;