Ces trois méthodes sont valables quel que soit le document et seront donc reprises par héritage dans toutes les sous-classes.. Outre la création du parseur, la principale caractéristique
Trang 1analyse du document, enfin destruction du parseur Ces trois méthodes sont valables quel que soit le document et seront donc reprises par héritage dans toutes les sous-classes Outre la création du parseur, la principale caractéristique du constructeur est l’appel à la fonction xml_set_object() qui indique que le parseur est intégré
à l’objet courant ($this) et que les déclencheurs sont des méthodes de cet objet
La méthode parse() est implantée de manière un peu plus robuste que celle de notre premier exemple En particulier :
1 le fichier est analysé par tranche de 4 096 octets pour éviter de charger en mémoire un document trop volumineux ; la fonction xml_parse() prend en troisième argument un indicateur de fin de fichier (ici retourné par la fonction feof()) qui indique qu’on a atteint la dernière tranche du document ;
2 une gestion d’erreurs est mise en place, en testant le code retour de xml_parse(), et en appelant le cas échéant des fonctions décrivant l’erreur : une description détaillée de toutes ces fonctions XML/PHP est donnée dans l’annexe C
En plus de ces trois méthodes, la classe SAX propose une implantation « par
défaut » des déclencheurs associés aux balises ouvrantes, fermantes et aux nœuds de texte (ou données caractères) Dans une implantation plus complète, la classe devrait également gérer les instructions de traitement, entités externes et autres catégories syntaxiques XML
Que font ces méthodes ? Le principe est de regarder, pour un élément dont le
nom NomEl´ ement est transmis en paramètre, si la classe comprend une méthode debutNomEl´ ement , une méthode finNomEl´ ement , ou les deux Si une telle
méthode existe, elle est appelée Sinon il y a deux possibilités :
1 soit l’objet $this est une instance de la super-classe SAX, et on affiche un
message indiquant qu’une balise ouvrante ou fermante selon le cas a été rencontrée ;
2 soit l’objet est une instance d’une sous-classe, et dans ce cas l’absence d’une méthode pour l’élément indique que ce dernier doit être ignoré
En d’autres termes, un objet de la classe SAX peut être utilisé comme notre
premier module, page 335, pour afficher le marquage du document au fur et à
mesure qu’il est rencontré Un objet d’une sous-classe de SAX en revanche doit
explicitement fournir des méthodes de traitement des éléments, sinon il ne se passe rien
Les méthodes debutElement() et finElement() s’appuient sur les fonctions PHP suivantes :
• method_exists() qui teste si une méthode est définie pour un objet,
• call_user_func() qui permet de déclencher l’exécution d’une méthode pour un objet2,
2 En PHP, on désigne une fonction par son nom, et une méthode par un tableau contenant une paire (objet, nom de la méthode).
Trang 2• enfin get_class() qui renvoie, en minuscules, le nom de la classe dont l’objet courant est une instance
Voici la mise en œuvre de ces fonctions dans la méthode debutElement() :
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 = " " ;
}
Pour bien comprendre l’intérêt de cette conception qui peut sembler compliquée
au premier abord, il suffit de constater que la création d’un analyseur pour un type
donné de document se résume maintenant à créer une sous-classe de SAX et à placer dans cette sous-classe des méthodes debutNom et finNom spécifiques aux noms d’éléments du type de document Voici la classe SAXFilm, sous-classe de SAX (noter
le mot-clé extends), qui permet d’analyser nos documents contenant des films (voir l’exemple du documentKillBill.xml, page 331)
Exemple 8.16 webscope/application/classes/SAXFilm.php : Spécialisation de la classe pour traiter des films
<? php
/ ∗ ∗
∗ C l a s s e d ’ a n a l y s e a v e c l e p a r s e u r SAX d ’ un d o c u m e n t XML
∗ r e p r é s e n t a n t un f i l m a v e c s e s a c t e u r s
∗ /
r e q u i r e _ o n c e ( "SAX php " ) ;
c l a s s SAXFilm e x t e n d s SAX
{
/ / D é c l a r a t i o n d e s v a r i a b l e s s t o c k a n t l e r é s u l t a t d e l ’ a n a l y s e / / p r i v a t e $ f i l m s , $ n b _ f i l m s , $ i _ a c t e u r ;
/ / C o n s t r u c t e u r
f u n c t i o n SAXFilm ( $ c o d a g e )
{
/ / On a p p e l l e l e c o n s t r u c t e u r d e l a s u p e r −c l a s s e
p a r e n t : : _ _ c o n s t r u c t ( $ c o d a g e ) ;
Trang 3/ / On i n i t i a l i s e l e s v a r i a b l e s d e l a s o u s −c l a s s e
$ t h i s−>f i l m s = a r r a y ( ) ;
$ t h i s−>n b _ f i l m s = 0 ;
$ t h i s−>i _ a c t e u r = 0 ;
}
/ / On d é f i n i t l e s d é c l e n c h e u r s p o u r l e s d i f f é r e n t s é l é m e n t s d e FILM
p r o t e c t e d f u n c t i o n finTITRE ( $ p a r s e u r , $nom )
{ $ t h i s−>f i l m s [ $ t h i s −>n b _ f i l m s ] [ ’ t i t r e ’ ] = $ t h i s −>donnees ; }
p r o t e c t e d f u n c t i o n finANNEE ( $ p a r s e u r , $nom )
{ $ t h i s−>f i l m s [ $ t h i s −>n b _ f i l m s ] [ ’ annee ’ ] = $ t h i s −>donnees ; }
p r o t e c t e d f u n c t i o n finCODE_PAYS ( $ p a r s e u r , $nom )
{ $ t h i s−>f i l m s [ $ t h i s −>n b _ f i l m s ] [ ’ c ode _pa y s ’ ] = $ t h i s −>donnees ; }
p r o t e c t e d f u n c t i o n finGENRE ( $ p a r s e u r , $nom )
{ $ t h i s−>f i l m s [ $ t h i s −>n b _ f i l m s ] [ ’ g e nr e ’ ] = $ t h i s −>donnees ; }
p r o t e c t e d f u n c t i o n finRESUME ( $ p a r s e u r , $nom )
{ $ t h i s−>f i l m s [ $ t h i s −>n b _ f i l m s ] [ ’ resume ’ ] = $ t h i s −>donnees ; }
/ / P o u r l e m e t t e u r e n s c è n e
p r o t e c t e d f u n c t i o n debutREALISATEUR ( $ p a r s e u r , $nom , $ a t t r ) {
$ t h i s−>f i l m s [ $ t h i s −>n b _ f i l m s ] [ ’ n o m _ r e a l i s a t e u r ’ ]
= $ a t t r [ ’NOM’ ] ;
$ t h i s−>f i l m s [ $ t h i s −>n b _ f i l m s ] [ ’ p r e n o m _ r e a l i s a t e u r ’ ]
= $ a t t r [ ’PRENOM ’ ] ;
$ t h i s−>f i l m s [ $ t h i s −>n b _ f i l m s ] [ ’ a n n e e _ r e a l i s a t e u r ’ ]
= $ a t t r [ ’ANNEE_NAISSANCE ’ ] ;
}
/ / P o u r un a c t e u r
p r o t e c t e d f u n c t i o n debutACTEUR ( $ p a r s e u r , $nom , $ a t t r )
{
$ t h i s−>f i l m s [ $ t h i s −>n b _ f i l m s ] [ ’nom ’ ] [ $ t h i s −>i _ a c t e u r ]
= $ a t t r [ ’NOM’ ] ;
$ t h i s−>f i l m s [ $ t h i s −>n b _ f i l m s ] [ ’ prenom ’ ] [ $ t h i s −>i _ a c t e u r ]
= $ a t t r [ ’PRENOM ’ ] ;
$ t h i s−>f i l m s [ $ t h i s −>n b _ f i l m s ] [ ’ a n n e e _ n a i s s a n c e ’ ] [ $ t h i s −>
i _ a c t e u r ]
= $ a t t r [ ’ANNEE_NAISSANCE ’ ] ;
$ t h i s−>f i l m s [ $ t h i s −>n b _ f i l m s ] [ ’ nom_role ’ ] [ $ t h i s −>i _ a c t e u r ]
= $ a t t r [ ’NOM_ROLE ’ ] ;
$ t h i s−>i _ a c t e u r ++;
}
/ / Au d é b u t d ’ un é l é m e n t FILM : on i n c r é m e n t e l e c o m p t e u r d e / / f i l m s ,
/ / on i n i t i a l i s e l e c o m p t e u r d e s a c t e u r s e t l e s t a b l e a u x
p r o t e c t e d f u n c t i o n debutFILM ( $ p a r s e u r , $nom )
{
$ t h i s−>n b _ f i l m s ++;
Trang 4$ t h i s−>f i l m s [ $ t h i s −>n b _ f i l m s ] = a r r a y ( ) ;
$ t h i s−>f i l m s [ $ t h i s −>n b _ f i l m s ] [ ’nom ’ ] = a r r a y ( ) ;
$ t h i s−>f i l m s [ $ t h i s −>n b _ f i l m s ] [ ’ prenom ’ ] = a r r a y ( ) ;
$ t h i s−>f i l m s [ $ t h i s −>n b _ f i l m s ] [ ’ a n n e e _ n a i s s a n c e ’ ] = a r r a y ( ) ;
$ t h i s−>f i l m s [ $ t h i s −>n b _ f i l m s ] [ ’ nom_role ’ ] = a r r a y ( ) ;
$ t h i s−>i _ a c t e u r = 0 ;
}
/∗ ∗∗∗∗∗∗∗∗∗∗ P a r t i e p u b l i q u e ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ ∗ /
/ / R é c u p é r a t i o n d ’ un f i l m
p u b l i c f u n c t i o n g e t N b F i l m ( )
{ r e t u r n $ t h i s−>n b _ f i l m s ; }
p u b l i c f u n c t i o n g e t F i l m ( $ i d _ f i l m )
{
i f ( $ i d _ f i l m > 0 and $ i d _ f i l m <= $ t h i s−>n b _ f i l m s )
r e t u r n $ t h i s−>f i l m s [ $ i d _ f i l m ] ;
e l s e
{
/ / M a i s non , c e t i d n ’ e x i s t e p a s ! ! !
t r i g g e r _ e r r o r ( " I n d e x i n c o r r e c t p o u r a c c é d e r à un f i l m :
$ i d _ f i l m " ) ;
r e t u r n a r r a y ( ) ;
}
}
}
Cette sous-classe comprend essentiellement des méthodes pour traiter les
élé-ments spécifiques d’un document <Film> : tout ce qui relève de la création et
de l’utilisation du parseur est hérité de la classe SAX, et donc automatiquement disponible pour les objets de la classe SAXFilm.
Dans le cas des éléments titre, annee, code_pays, etc., la chaîne à extraire est
le contenu de l’élément, autrement dit le nœud de type texte situé sous l’élément dans l’arborescence On récupère cette chaîne en déclenchant une fonction quand
on rencontre la balise fermante On sait alors que la chaîne est mémorisée dans l’attribut $this->donnees, et on la stocke dans le tableau des films
Dans le cas des éléments Realisateur ou Acteur, les chaînes de caractères à extraire sont les attributs de l’élément On déclenche cette fois une fonction sur la balise ouvrante qui se charge de recopier le tableau des attributs dans $tab_film
Au moment de l’analyse du document, l’existence de ces méthodes sera détectée
par debutElement() ou finElement(), héritées de la classe SAX ; elles seront
donc automatiquement invoquées au moment approprié
Une dernière remarque : le constructeur de la classe SAXFilm initialise les
données qui sont propres aux films Il faut également appeler le constructeur de
la super-classe SAX puisque ce dernier a en charge la création du parseur Cet
Trang 5appel du constructeur des parents dans la hiérarchie de spécialisation n’est pas automatique en PHP
Voici pour finir le script associé au formulaire qui permet de transmettre un document XML pour l’insérer dans la base MySQL La création d’un objet $filmXML,
instance de la classe SAXFilm, permet d’analyser de manière complètement
transpa-rente le contenu du document et de récupérer les valeurs décrivant un film3 Pour
le contrôle des données et l’insertion dans la base, on fait appel aux fonctions du modèle implantées dansFilm.phppar extension de la classe TableBD
f u n c t i o n i m p o r t ( )
{
/ / D é f i n i t i o n du t i t r e
$ t h i s−>vue−>t i t r e _ p a g e = " Import de données XML" ;
/ / C o n t r ô l e d e l a s e s s i o n
$ t h i s−>c o n t r o l e A c c e s ( ) ;
/ / C r é a t i o n du p a r s e u r p o u r l e s f i l m s
$film_XML = new SAXFilm ( " ISO−8859−1 " ) ;
/ / A n a l y s e du d o c u m e n t
i f ( ! i s S e t ( $_FILES [ ’ f i c h i e r X M L ’ ] ) ) {
$ t h i s−>vue−>contenu = " I l f a u t i n d i q u e r un f i c h i e r XML <br
/ > " ;
echo $ t h i s−>vue−>r e n d e r ( " page " ) ;
r e t u r n ;
}
e l s e {
$film_XML−>p a r s e ( $_FILES [ ’ fichierXML ’ ] [ ’ tmp_name ’ ] ) ;
}
/ / On i n s è r e , s i a u c u n e e r r e u r n ’ e s t s u r v e n u e
i f ( ! $film_XML−>e r r e u r R e n c o n t r e e ( ) ) {
$ f i l m = $film_XML−>g e t F i l m (1) ;
/ / On i n s t a n c i e l e m o d è l e " F i l m " ( v o i r l e c o n t r ô l e u r S a i s i e )
$ t b l _ f i l m = new F i l m ( $ t h i s−>bd ) ;
/ / On c r é e un o b j e t à p a r t i r d e s d o n n é e s du t a b l e a u HTTP
$ t b l _ f i l m−>nouveau ( $ f i l m ) ;
/ / C o n t r ô l e d e s v a l e u r s r e ç u e s
$ m e s s a g e = $ t b l _ f i l m−>c o n t r o l e ( ) ;
/ / V é r i f i c a t i o n d e s v a l e u r s r é c u p é r é e s d a n s l e d o c u m e n t
i f ( $ m e s s a g e ) {
3 Ce code fonctionne également pour un document contenant plusieurs films, mais pour simplifier
nous ne traitons que le premier film rencontré.