Tout d’abord, je dois admettre que j’adore les standards informatiques. Si tout le monde suivait les normes de l’industrie, Internet serait un meilleur média. L’utilisation de formats d’échange de données standardisés rend réalisables des modèles informatiques ouverts et indépendants de la plate-forme. C'est pourquoi je suis un passionné de XML.
Heureusement, mon langage de script préféré prend non seulement en charge XML, mais il le prend de plus en plus en charge. PHP me permet de publier rapidement des documents XML sur Internet, de collecter des informations statistiques sur les documents XML et de convertir des documents XML dans d'autres formats. Par exemple, j'utilise souvent les capacités de traitement XML de PHP pour gérer les articles et les livres que j'écris en XML.
Dans cet article, je discuterai de toute utilisation de l'analyseur Expat intégré à PHP pour traiter des documents XML. A travers des exemples, je démontrerai la méthode de traitement d'Expat. En même temps, l'exemple peut vous montrer comment :
Créer votre propre fonction de traitement
Conversion de documents XML en vos propres structures de données PHP
Introduction
L'analyseur d'Expat XML, également appelé processeur XML, permet aux programmes d'accéder à la structure et au contenu des documents XML. Expat est un analyseur XML pour le langage de script PHP. Il est également utilisé dans d'autres projets, tels que Mozilla, Apache et Perl.
Qu'est-ce qu'un analyseur basé sur des événements ?
Il existe deux types fondamentaux d'analyseurs XML :
Analyseurs arborescents : convertissent les documents XML en structures arborescentes. Ce type d'analyseur analyse l'intégralité de l'article tout en fournissant une API pour accéder à chaque élément de l'arborescence résultante. Son standard commun est le DOM (Document Object Model).
Analyseur basé sur les événements : traitez les documents XML comme une série d'événements. Lorsqu'un événement spécial se produit, l'analyseur appellera la fonction fournie par le développeur pour le gérer.
L'analyseur basé sur les événements a une vue du document XML axée sur les données, ce qui signifie qu'il se concentre sur la partie données du document XML plutôt que sur sa structure. Ces analyseurs traitent le document du début à la fin et rapportent des événements tels que - début d'élément, fin d'élément, début de données de fonctionnalité, etc. - à l'application via des fonctions de rappel. Ce qui suit est un exemple de document XML pour « Hello-World » :
<message d'accueil
>
Bonjour le monde
</greeting>
L'analyseur basé sur les événements rapportera trois événements :
élément de début : salutation
Le début de l'élément CDATA, la valeur est : Hello World
Élément de fin : salutation
Contrairement aux analyseurs arborescents, les analyseurs basés sur les événements ne produisent pas de structure décrivant le document. Dans les éléments CDATA, l'analyseur basé sur les événements ne vous permettra pas d'obtenir les informations de bienvenue de l'élément parent.
Cependant, il fournit un accès de niveau inférieur, ce qui permet une meilleure utilisation des ressources et un accès plus rapide. De cette façon, il n’est pas nécessaire de mettre l’intégralité du document en mémoire ; en fait, l’intégralité du document peut même être plus grande que la valeur réelle de la mémoire.
Expat est un tel analyseur basé sur des événements. Bien entendu, si vous utilisez Expat, il peut également générer une arborescence native complète en PHP si nécessaire.
L'exemple Hello-World ci-dessus inclut le format XML complet. Mais il n'est pas valide car il n'y a ni DTD (Document Type Definition) qui lui est associé ni DTD intégré.
Pour Expat, cela ne fait aucune différence : Expat est un analyseur qui ne vérifie pas la validité et ignore donc toute DTD associée au document. Il convient cependant de noter que le document doit encore être entièrement formaté, sinon Expat (comme les autres analyseurs compatibles XML) s'arrêtera avec un message d'erreur.
En tant qu'analyseur qui ne vérifie pas la validité, la vitesse et la légèreté d'Exapt le rendent bien adapté aux applications Internet.
Compilation d'Expat
Expat peut être compilé en version PHP3.0.6 (ou supérieure). À partir d'Apache 1.3.9, Expat a été inclus dans Apache. Sur les systèmes Unix, vous pouvez le compiler en PHP en configurant PHP avec l'option -with-xml.
Si vous compilez PHP en tant que module Apache, Expat sera inclus par défaut dans Apache. Sous Windows, vous devez charger la bibliothèque de liens dynamiques XML.
Exemples XML : XMLstats
Une façon d'en apprendre davantage sur les fonctions d'Expat consiste à utiliser des exemples. L'exemple dont nous allons discuter utilise Expat pour collecter des statistiques sur les documents XML.
Pour chaque élément du document, les informations suivantes seront affichées :
le nombre de fois que l'élément est utilisé dans le document
La quantité de données de caractères dans cet élément
l'élément parent de l'élément
éléments enfants de l'élément
Remarque : à des fins de démonstration, nous utilisons PHP pour générer une structure permettant de sauvegarder l'élément parent et l'élément enfant de l'élément.
préparée
pour générer l'instance d'analyseur XML est xml_parser_create(). Cette instance sera utilisée pour toutes les fonctions futures. Cette idée est très similaire à la balise de connexion de la fonction MySQL en PHP. Avant d'analyser le document, les analyseurs basés sur des événements nécessitent généralement que vous enregistriez une fonction de rappel - à appeler lorsqu'un événement spécifique se produit. Expat n'a pas d'événements d'exception. Il définit les sept événements possibles suivants :
objet analyse XML fonction description
élément xml_set_element_handler()
données de caractère de début et de fin de l'élément xml_set_character_data_handler() début de données de caractère
entité externe xml_set_external_entity_ref_handler() entité externe Entité externe non analysée
xml_set_unparsed_entity_decl_handler ( ) L'occurrence d'une
instruction de traitement d'entité externe non résolue xml_set_processing_instruction_handler() L'occurrence d'une
déclaration de notation d'instruction de traitement xml_set_notation_decl_handler() L'occurrence d'une déclaration de notation
par défaut xml_set_default_handler() Autres événements sans fonction de gestionnaire spécifiée
Toutes les fonctions de rappel doivent utiliser une instance de analyseur comme son premier paramètre (il existe d’autres paramètres en plus).
Pour l’exemple de script à la fin de cet article. Ce que vous devez noter, c'est qu'il utilise à la fois des fonctions de traitement d'éléments et des fonctions de traitement de données de caractères. La fonction de gestionnaire de rappel de l'élément est enregistrée via xml_set_element_handler().
Cette fonction prend trois paramètres :
une instance de l'analyseur
Le nom de la fonction de rappel qui gère l'élément de démarrage
Le nom de la fonction de rappel qui gère l'élément de fermeture
La fonction de rappel doit exister lorsque l'analyse du document XML commence. Ils doivent être définis en cohérence avec les prototypes décrits dans le manuel PHP.
Par exemple, Expat transmet trois arguments à la fonction de gestionnaire pour l'élément start. Dans l'exemple de script, il est défini comme suit :
function start_element($parser, $name, $attrs)
Le premier paramètre est l'identifiant de l'analyseur, le deuxième paramètre est le nom de l'élément de départ et le troisième paramètre contient tous les attributs et valeurs du tableau d'éléments.
Une fois que vous aurez commencé à analyser le document XML, Expat appellera votre fonction start_element() et transmettra les paramètres chaque fois qu'il rencontrera l'élément start.
L'option Case Folding de XML
utilise la fonction xml_parser_set_option () pour désactiver l'option Case Folding. Cette option est activée par défaut, ce qui entraîne la conversion automatique des noms d'éléments transmis aux fonctions du gestionnaire en majuscules. Mais XML est sensible à la casse (la casse est donc très importante pour les documents XML statistiques). Pour notre exemple, l’option de pliage du boîtier doit être désactivée.
Analyser le document
Après avoir terminé toutes les préparations, le script peut enfin analyser le document XML :
Xml_parse_from_file(), une fonction personnalisée, ouvre le fichier spécifié dans le paramètre et l'analyse dans une taille de 4 Ko.
xml_parse(), comme xml_parse_from_file(), renverra false lorsqu'une erreur se produit, c'est-à-dire lorsque le document XML n'est pas entièrement formaté.
Vous pouvez utiliser la fonction xml_get_error_code() pour obtenir le code numérique de la dernière erreur. Transmettez ce code numérique à la fonction xml_error_string() pour obtenir les informations sur le texte d'erreur.
Affiche le numéro de ligne actuel du XML, ce qui facilite le débogage.
Pendant le processus d'analyse, la fonction de rappel est appelée.
Décrire la structure du document
Lors de l'analyse d'un document, la question qui doit être abordée avec Expat est : comment maintenir une description de base de la structure du document ?
Comme mentionné précédemment, l'analyseur basé sur les événements lui-même ne produit aucune information structurelle.
Cependant, la structure des balises est une fonctionnalité importante de XML. Par exemple, la séquence d'éléments <book><title> signifie quelque chose de différent de <figure><title>. Cela dit, n'importe quel auteur vous dira que les titres de livres et les titres d'images n'ont rien à voir les uns avec les autres, même s'ils utilisent tous deux le terme « titre ». Par conséquent, afin de traiter efficacement le XML avec un analyseur basé sur les événements, vous devez utiliser vos propres piles ou listes pour conserver les informations structurelles sur le document.
Afin de refléter la structure du document, le script doit connaître au moins l'élément parent de l'élément actuel. Cela n'est pas possible avec l'API d'Exapt. Elle rapporte uniquement les événements de l'élément actuel sans aucune information contextuelle. Par conséquent, vous devez créer votre propre structure de pile.
L'exemple de script utilise une structure de pile premier entré, dernier sorti (FILO). Grâce à un tableau, la pile sauvegardera tous les éléments de départ. Pour la fonction de traitement de l'élément de démarrage, l'élément actuel sera poussé vers le haut de la pile par la fonction array_push(). En conséquence, la fonction de traitement des éléments de fin supprime l'élément supérieur via array_pop().
Pour la séquence <book><title></title></book>, la pile est renseignée comme suit :
start element book : attribuez "book" au premier élément de la pile ($stack[0]).
Titre de l'élément de départ : attribuez "titre" en haut de la pile ($stack[1]).
Titre de l'élément de fin : supprimez l'élément supérieur de la pile ($stack[1]).
Titre de l'élément de fin : supprimez l'élément supérieur de la pile ($stack[0]).
PHP3.0 implémente l'exemple en contrôlant manuellement l'imbrication des éléments via une variable $profondeur. Cela rend le script plus complexe. PHP4.0 utilise les fonctions array_pop() et array_push() pour rendre le script plus concis.
Collecte de données
Afin de collecter des informations sur chaque élément, le script doit mémoriser les événements de chaque élément. Enregistrez tous les différents éléments du document en utilisant une variable de tableau globale $elements. Les éléments du tableau sont des instances de la classe d'éléments et ont 4 propriétés (variables de la classe)
$count - le nombre de fois où l'élément a été trouvé dans le document
$chars - Nombre d'octets d'événements de caractères dans l'élément
$parents - élément parent
$childs - éléments enfants
Comme vous pouvez le constater, enregistrer des instances de classe dans un tableau est un jeu d’enfant.
Remarque : Une fonctionnalité de PHP est que vous pouvez parcourir toute la structure de classe via une boucle while(list() = each()), tout comme vous parcourez l'intégralité du tableau correspondant. Toutes les variables de classe (et les noms de méthodes lorsque vous utilisez PHP3.0) sont affichées sous forme de chaînes.
Lorsqu'un élément est trouvé, nous devons incrémenter son compteur correspondant pour savoir combien de fois il apparaît dans le document. L'élément count dans l'élément $elements correspondant est également incrémenté de un.
Nous devons également faire savoir à l'élément parent que l'élément actuel est son élément enfant. Par conséquent, le nom de l'élément actuel sera ajouté à l'élément dans le tableau $childs de l'élément parent. Enfin, l'élément actuel doit se rappeler qui est son parent. Par conséquent, l'élément parent est ajouté à l'élément dans le tableau $parents de l'élément actuel.
Affichage des statistiques
Le code restant parcourt le tableau $elements et ses sous-tableaux pour afficher ses statistiques. Il s'agit de la boucle imbriquée la plus simple. Bien qu'elle génère des résultats corrects, le code n'est ni concis ni doté de compétences particulières. Il s'agit simplement d'une boucle que vous pouvez utiliser quotidiennement pour terminer votre travail.
Les exemples de script sont conçus pour être invoqués depuis la ligne de commande via l'approche CGI de PHP. Par conséquent, le format de sortie des résultats statistiques est le format texte. Si vous souhaitez utiliser le script sur Internet, vous devez alors modifier la fonction de sortie pour générer le format HTML.
Exapt est un analyseur XML pour PHP
.
En tant qu'analyseur événementiel, il ne produit pas de description structurelle du document. Mais en fournissant un accès de bas niveau, cela permet une meilleure utilisation des ressources et un accès plus rapide.
En tant qu'analyseur qui ne vérifie pas la validité, Expat ignore les DTD attachées aux documents XML, mais il s'arrêtera avec un message d'erreur si le document n'est pas bien formé.
Fournir des gestionnaires d'événements pour traiter les documents
Créez vos propres structures d'événements, telles que des piles et des arborescences, pour tirer parti du balisage d'informations structurées XML.
De nouveaux programmes XML apparaissent chaque jour et la prise en charge de XML par PHP est constamment renforcée (par exemple, la prise en charge de l'analyseur XML basé sur DOM LibXML a été ajoutée).
Avec PHP et Expat, vous pouvez vous préparer aux normes à venir qui sont valides, ouvertes et indépendantes de la plateforme.
Exemple
<?
/*************************************************** ***** *****************************
* Nom : exemple d'analyse XML : statistiques d'informations sur les documents XML
* décrire
* Cet exemple utilise l'analyseur Expat de PHP pour collecter et compter les informations du document XML (par exemple : le nombre d'occurrences de chaque élément, les éléments parents et les éléments enfants
* Fichier XML en paramètre./xmlstats_PHP4.php3 test.xml
* $Requires : Expat Requirements : Expat PHP4.0 est compilé en mode CGI
************************************************** * ***************************/
// Le premier paramètre est le fichier XML
$file = $argv[1];
// Initialisation des variables
$éléments = $pile = tableau();
$total_elements = $total_chars = 0;
//Classe d'éléments de base
élément de classe
{
var $compte = 0;
var $caractères = 0;
var $parents = tableau();
var $enfant = tableau();
}
// Fonction pour analyser les fichiers XML
fonction xml_parse_from_file($parser, $file)
{
si(!file_exists($fichier))
{
die("Impossible de trouver le fichier "$file".");
}
if(!($fp = @fopen($file, "r")))
{
die("Impossible d'ouvrir le fichier "$file".");
}
while($data = fread($fp, 4096))
{
if(!xml_parse($parser, $data, feof($fp)))
{
retourner(faux);
}
}
fclose($fp);
return(true);
}
// Fonction de résultat de sortie (forme de boîte)
fonction print_box ($ titre, $ valeur)
{
printf("n+%'-60s+n", "");
printf("|%20s", "$titre:");
printf("%14s", $valeur);
printf("%26s|n", "");
printf("+%'-60s+n", "");
}
// Fonction de résultat de sortie (sous forme de ligne)
fonction print_line ($ titre, $ valeur)
{
printf("%20s", "$titre:");
printf("%15sn", $valeur);
}
// Fonction de tri
fonction mon_sort($a, $b)
{
return(is_object($a) && is_object($b) ? $b->count - $a->count: 0);
}
fonction start_element($parser, $name, $attrs)
{
global $elements, $stack;
// L'élément est-il déjà dans le tableau global $elements ?
si(!isset($elements[$nom]))
{
// Non - ajoute une instance de classe d'un élément
$element = nouvel élément ;
$éléments[$nom] = $élément ;
}
// Incrémente le compteur de cet élément de un
$elements[$name]->count++;
// Y a-t-il un élément parent ?
si(isset($stack[count($stack)-1]))
{
// Oui - attribue l'élément parent à $last_element
$last_element = $stack[count($stack)-1];
// Si le tableau d'éléments parent de l'élément actuel est vide, initialisez-le à 0
if(!isset($elements[$name]->parents[$last_element]))
{
$elements[$name]->parents[$last_element] = 0;
}
// Incrémente le compteur de l'élément parent de cet élément de un
$elements[$name]->parents[$last_element]++;
// Si le tableau d'éléments enfants de l'élément parent de l'élément courant est vide, il est initialisé à 0
if(!isset($elements[$last_element]-> enfants[$ nom]))
{
$elements[$last_element]->childs[$name] = 0;
}
// Ajoutez-en un au compteur d'élément enfant de l'élément parent de l'élément.
$elements[$last_element]->childs[$name]++;
}
//Ajoute l'élément actuel à la pile
array_push ($ pile, $ nom);
}
fonction stop_element($parser, $name)
{
global $stack;
// Supprime l'élément supérieur de la pile
array_pop($pile);
}
fonction char_data($parser, $data)
{
global $elements, $stack, $profondeur;
// Augmente le nombre de caractères de l'élément courant
$elements[$stack][count($stack)-1]]->chars += strlen(trim($data));
}
// Générer une instance d'analyseur
$parser = xml_parser_create();
// Définir la fonction de traitement
xml_set_element_handler($parser, "start_element", "stop_element");
xml_set_character_data_handler($parser, "char_data");
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
// Analyser le fichier
$ret = xml_parse_from_file($parser, $file);
si(!$ret)
{
die(sprintf("Erreur XML : %s à la ligne %d",
xml_error_string(xml_get_error_code($parser)),
xml_get_current_line_number($parser)));
}
// Libère l'analyseur
xml_parser_free($parser);
// Libère l'élément d'assistance
unset($elements["current_element"]);
unset($elements["last_element"]);
// Trier selon le nombre d'éléments
uasort($elements, "my_sort");
// Parcourez $elements pour collecter les informations sur les éléments
while(list($nom, $element) = each($elements))
{
print_box("Nom de l'élément", $name);
print_line("Nombre d'éléments", $element->count);
print_line("Nombre de caractères", $element->chars);
printf("n%20sn", "* Éléments parents");
// Parcourez le parent de l'élément et affichez le résultat
while(list($key, $value) = each($element->parents))
{
print_line($clé, $valeur);
}
if(count($element->parents) == 0)
{
printf("%35sn", "[élément racine]");
}
// Parcourez l'enfant de cet élément et affichez le résultat
printf("n%20sn", "* Éléments enfants");
while(list($key, $value) = each($element->childs))
{
print_line($clé, $valeur);
}
si (compte ($ élément-> enfants) == 0)
{
printf("%35sn", "[aucun enfant]");
}
$total_elements += $element->count;
$total_chars += $element->chars ;
}
// résultat final
print_box("Total des éléments", $total_elements);
print_box("Total de caractères", $total_chars);
?>