La fonction ne permet pas de savoir de quel élément il s’agit rappelons que les éléments et le texte constituent des nœuds distincts dans l’arborescence d’un document XML, et sont donc t
Trang 1f u n c t i o n d o n n e e s C a r a c t e r e s ( $ p a r s e r , $ c h a i n e )
{
g l o b a l $ t a b _ e l e m e n t s , $ e l e m e n t _ c o u r a n t ;
i f ( t r i m ( $ c h a i n e ) != " " )
$ t a b _ e l e m e n t s [ $ e l e m e n t _ c o u r a n t ] = $ c h a i n e ;
}
On reçoit en argument la chaîne de caractères constituant le contenu du nœud de texte De tels nœuds sont très souvent constitués uniquement d’espaces ou de retours
à la ligne, quand il servent uniquement à la mise en forme du document On élimine ici ces espaces avec la fonction PHP trim() et on vérifie que la chaîne obtenue n’est pas vide On sait alors qu’on a affaire au contenu d’un élément
La fonction ne permet pas de savoir de quel élément il s’agit (rappelons que les éléments et le texte constituent des nœuds distincts dans l’arborescence d’un document XML, et sont donc traités séparément par le parseur) La seule solution est de s’appuyer sur une variable globale, $element_courant qui stocke le nom du dernier élément rencontré (voir la fonction debutElement()) On utilise ce nom pour mémoriser le contenu dans le tableau $tab_elements, lui aussi déclaré comme une variable globale
Ce style de programmation, assez laborieux, est imposé par l’absence d’informa-tion sur le contexte quand une foncd’informa-tion est déclenchée On ne sait pas à quelle profondeur on est dans l’arbre, quels sont les éléments rencontrés auparavant ou ceux qui qui vont être rencontrés après, etc Cette limitation est le prix à payer pour l’efficacité du modèle d’analyse : le parseur se contente de parcourir le document une seule fois, détectant le marquage au fur et à mesure et déclenchant les fonctions appropriées
Le code ci-dessous montre comment faire appel au module, en l’appliquant au documentGladiator.xml(voir page 318)
Exemple 8.13 exemples/ExSAX.php:Exemple d’application du parseur
<?php
// Application des fonctions SAX
require ("SAX.php");
Header ("Content-type: text/plain");
// Analyse du document
$film = ParseFilm ("Gladiator.xml");
// Affichage des donn´ ees extraites
while ( list ($nom, $val) = each ($film))
echo "Nom : $nom Valeur : $val\n";
?>
Trang 2On obtient alors le résultat suivant (noter que les noms d’éléments sont mis en majuscules par le parseur, option par défaut qui peut être modifiée) :
Exemple 8.14 ResultatSAX.txt : Résultat de l’application du parseur
balise ouvrante de FILM
balise ouvrante de TITRE
balise fermante de TITRE
balise ouvrante de ANNEE
balise fermante de ANNEE
balise ouvrante de CODEPAYS
balise fermante de CODEPAYS
balise ouvrante de GENRE
balise fermante de GENRE
balise ouvrante de REALISATEUR
balise fermante de REALISATEUR
balise fermante de FILM
Nom : TITRE Valeur : Gladiator
Nom : ANNEE Valeur : 2000
Nom : CODEPAYS Valeur : USA
Nom : GENRE Valeur : Drame
L’approche très simple employée ici se généralise difficilement à des documents XML plus complexes comprenant des imbrications d’éléments, comme par exemple
un film avec son réalisateur et la liste de ses acteurs Le fait de devoir mémoriser dans des variables globales le positionnement du parseur dans le document rend rapidement la programmation assez laborieuse
Heureusement, une fonctionnalité très intéressante du parseur XML/PHP permet une intégration forte avec la programmation orientée-objet Nous montrons dans ce qui suit comment utiliser cette fonctionnalité C’est également l’occasion de revenir sur les notions de spécialisation et d’héritage de la programmation objet, présentées dans le chapitre 3
8.3.3 Une classe de traitement de documents XML
La fonction xml_set_object() permet d’associer un parseur XML et un objet, avec deux effets liés :
• les « déclencheurs » seront pris parmi les méthodes de l’objet (ou, plus préci-sément, de la classe dont l’objet est une instance) ;
• ces déclencheurs ont accès aux variables d’état de l’objet, ce qui évite d’avoir recours aux variables globales
On peut donc développer des classes, dédiées chacune à un type de document particulier (par exemple nos films), avec un style de programmation beaucoup plus élégant que celui employé précédemment Chaque classe fournit, sous forme de méthodes, des fonctionnalités de création du parseur, de gestion des erreurs, de défi-nition des déclencheurs, de lancement de l’analyse, etc Afin d’essayer d’être –encore
Trang 3une fois– le plus général possible, nous allons distinguer dans ces fonctionnalités
celles, génériques, qui sont identiques pour tous les types de document de celles qui sont spécifiques à un type de document donné Il serait dommage de dupliquer les
premières autant de fois qu’il y a de types de documents, avec les inconvénients évidents en termes de maintenance et de modification qui en découlent Il est donc souhaitable de recourir à la spécialisation objet qui permet de « factoriser » les fonctions génériques et de les rendre disponibles pour chaque classe traitant d’un type de document particulier
Le principe consiste à créer une (super-)classe qui regroupe les fonctions géné-riques au traitement d’un document par SAX, et à créer, par spécialisation, une sous-classe de cette super-classe qui peut réutiliser ses fonctionnalités (héritage), les redéfinir (surcharge), et lui en ajouter d’autres (extension) Voici le code de la super-classe Nous en décrivons plus bas les principales méthodes
Exemple 8.15 webscope/lib/SAX.php : Une classe générique de traitement d’un document XML
<? php
/∗ ∗
∗ C l a s s e g é n é r i q u e d ’ a p p e l aux f o n c t i o n s SAX d ’ a n a l y s e de
∗ d o c u m e n t s XML.
∗ C e t t e c l a s s e d o i t ê t r e s o u s −t y p é e p o u r c h a q u e t y p e de
∗ d o c u m e n t
∗ Au n i v e a u de l a s u p e r −c l a s s e on s e c o n t e n t e d ’ i n s t a n c i e r l e
∗ p a r s e u r ,
∗ d e g é r e r l e s m e s s a g e s d ’ e r r e u r , e t d ’ a f f i c h e r au f u r e t à
∗ m e s u r e
∗ l e c o n t e n u du d o c u m e n t a n a l y s é
∗ /
c l a s s SAX
{
p r i v a t e $ p a r s e u r ;
p r o t e c t e d $ d o n n e e s ; / / D o n n é e s c a r a c t è r e s r e n c o n t r é e s e n c o u r s
d ’ a n a l y s e
p r o t e c t e d $ e r r e u r _ r e n c o n t r e e , $ m e s s a g e ; / / I n d i c a t e u r e t
m e s s a g e d ’ e r r e u r
/ / C o n s t r u c t e u r d e l a c l a s s e
f u n c t i o n _ _ c o n s t r u c t ( $ c o d a g e )
{
/ / On i n s t a n c i e l e p a r s e u r
$ t h i s−>p a r s e u r = x m l _ p a r s e r _ c r e a t e ( $codage ) ;
/ / On i n d i q u e q u e l e s d é c l e n c h e u r s s o n t d e s m é t h o d e s d e l a / / c l a s s e
x m l _ s e t _ o b j e c t ( $ t h i s−>p a r s e u r , &$ t h i s ) ;
/ / Tous l e s noms d ’ é l é m e n t s e t d ’ a t t r i b u t s s e r o n t t r a d u i t s e n / / m a j u s c u l e s
Trang 4x m l _ p a r s e r _ s e t _ o p t i o n ( $ t h i s−>p a r s e u r , XML_OPTION_CASE_FOLDING,
t r u e ) ;
x m l _ s e t _ e l e m e n t _ h a n d l e r ( $ t h i s−>p a r s e u r , " debutElement " , "
f i n E l e m e n t " ) ;
x m l _ s e t _ c h a r a c t e r _ d a t a _ h a n d l e r ( $ t h i s−>p a r s e u r , "
d o n n e e s C a r a c t e r e s " ) ;
$ t h i s−>e r r e u r _ r e n c o n t r e e = 0 ;
}
/ / M é t h o d e g é n é r i q u e d e t r a i t e m e n t d e s d é b u t s d ’ é l é m e n t s
p r o t e c t e d f u n c t i o n d e b u t E l e m e n t ( $ p a r s e u r , $nom , $ a t t r s )
{
/ / On r e c h e r c h e s i u n e m é t h o d e nommée " d e b u t { NomElement } "
e x i s t e
i f ( m e t h o d _ e x i s t s ( $ t h i s , " debut$nom " ) ) {
c a l l _ u s e r _ f u n c ( a r r a y ( $ t h i s , " debut$nom " ) , $ p a r s e u r , $nom ,
$ a t t r s ) ; }
e l s e i f ( g e t _ c l a s s ( $ t h i s ) == " s a x " ) {
echo " Début d ’ é l é m e n t : &l t ; " $nom "&g t ; \ n " ;
}
/ / E f f a c e m e n t d e s d o n n é e s c a r a c t è r e s
$ t h i s−>donnees = " " ;
}
/ / M é t h o d e g é n é r i q u e d e t r a i t e m e n t d e s f i n s d ’ é l é m e n t
p r o t e c t e d f u n c t i o n f i n E l e m e n t ( $ p a r s e u r , $nom )
{
/ / On r e c h e r c h e s i u n e m é t h o d e nommée " f i n { NomElement } "
/ / e x i s t e
i f ( m e t h o d _ e x i s t s ( $ t h i s , " fin$nom " ) ) {
c a l l _ u s e r _ f u n c ( a r r a y ( $ t h i s , " fin$nom " ) , $ p a r s e u r , $nom ) ;
}
e l s e i f ( g e t _ c l a s s ( $ t h i s ) == " s a x " ) {
echo " F i n d ’ é l é m e n t : &l t ; / " $nom "&g t ; \ n " ;
}
}
/ / P o u r l e s d o n n é e s , on s t o c k e s i m p l e m e n t au f u r e t à m e s u r e / / d a n s l a p r o p r i é t é $ t h i s −>d o n n e e s
p r o t e c t e d f u n c t i o n d o n n e e s C a r a c t e r e s ( $ p a r s e u r , $ c h a i n e )
{
/ / On n e p r e n d p a s l e s c h a î n e s v i d e s ou n e c o n t e n a n t q u e d e s / / b l a n c s
i f ( ! empty ( $ c h a i n e ) ) $ t h i s−>donnees = $chaine ;
}
Trang 5/ / M é t h o d e p o u r a n a l y s e r l e d o c u m e n t
p u b l i c f u n c t i o n p a r s e ( $ f i c h i e r )
{
/ / O u v e r t u r e du f i c h i e r
i f ( ! ( $ f = f o p e n ( $ f i c h i e r , " r " ) ) ) {
t r i g g e r _ e r r o r ( " I m p o s s i b l e d ’ o u v r i r l e f i c h i e r $ f i c h i e r \n " , E_USER_ERROR ) ;
r e t u r n ;
}
/ / A n a l y s e du c o n t e n u du d o c u m e n t
w h i l e ( $ d a t a = f r e a d ( $ f , 4 0 9 6 ) ) {
i f ( ! x m l _ p a r s e ( $ t h i s−>p a r s e u r , $data , f e o f ( $ f ) ) ) {
$ t h i s−>e r r e u r ( " E r r e u r r e n c o n t r é e l i g n e "
x m l _ e r r o r _ s t r i n g ( x m l _ g e t _ e r r o r _ c o d e ( $ t h i s−>p a r s e u r ) )
"%de $ f i c h i e r : "
x m l _ g e t _ c u r r e n t _ l i n e _ n u m b e r ( $ t h i s−>p a r s e u r ) ) ;
r e t u r n ; }
}
f c l o s e ( $ f ) ;
}
/ / D e s t r u c t e u r d e l a c l a s s e
f u n c t i o n _ _ d e s t r u c t ( )
{
x m l _ p a r s e r _ f r e e ( $ t h i s−>p a r s e u r ) ;
}
/ / F o n c t i o n r e t o u r n a n t l e m e s s a g e d ’ e r r e u r
p u b l i c f u n c t i o n m e s s a g e E r r e u r ( $ m e s s a g e )
{
r e t u r n $ t h i s−>message ;
}
/ / F o n c t i o n i n d i q u a n t s i u n e e r r e u r e s t s u r v e n u e
p u b l i c f u n c t i o n e r r e u r R e n c o n t r e e ( ) {
r e t u r n $ t h i s−>e r r e u r _ r e n c o n t r e e ;
}
/ / F o n c t i o n t r a i t a n t u n e e r r e u r
f u n c t i o n e r r e u r ( $ m e s s a g e )
{
t r i g g e r _ e r r o r ( $ m e s s a g e , E_USER_ERROR ) ;
}
}
? >
La classe comprend trois méthodes, construct() (le constructeur), parse()
et destruct() (le destructeur), qui correspondent respectivement aux trois phases de l’analyse d’un document : création du parseur, ouverture du fichier et