Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
XML::Reader_fr(3)     User Contributed Perl Documentation    XML::Reader_fr(3)

NAME
       XML::Reader_fr -	Lire du	XML avec des informations du chemin, conduit
       par un parseur d'extraction.

TRADUCTION
       This document is	the French translation from English of the module
       XML::Reader. In order to	get the	Perl source code of the	module,	please
       see file	XML/Reader.pm

       Ce document est une traduction FranA<section>aise de l'Anglais du
       module XML::Reader. Pour	obtenir	la source Perl du module, consultez le
       fichier XML/Reader.pm

SYNOPSIS
	 use XML::Reader qw(XML::Parser);

	 my $text = q{<init>n <?test pi?> t<page node="400">m <!-- remark --> r</page></init>};

	 my $rdr = XML::Reader->new(\$text);
	 while ($rdr->iterate) {
	     printf "Path: %-19s, Value: %s\n",	$rdr->path, $rdr->value;
	 }

       Ce programme crA(C)e le rA(C)sultat suivant:

	 Path: /init		  , Value: n t
	 Path: /init/page/@node	  , Value: 400
	 Path: /init/page	  , Value: m r
	 Path: /init		  , Value:

       On peut toujours	rajouter un eval {...} autours d'un appel
       XML::Reader->new(...) afin de vA(C)rifier que l'appel a rA(C)ussi:

	 my $rdr = eval{ XML::Reader->new('test.xml') }
	   or warn "Can't XML::Reader->new() because $@";

	 if ($rdr) {
	     # ... do something	with $rdr ...
	 }
	 else {
	     # ... do some error handling ...
	 }

UTILISATION
       Normalement, on n'utilise pas XML::Reader tout seul, on utilise plutA't
       XML::Reader::RS (qui utilise XML::Parser) ou on utilise XML::Reader::PP
       (qui utilise XML::Parsepp).

       Par contre, si on veut utiliser XML::Reader directement,	voici la
       procA(C)dure pour choisir entre XML::Parser et XML::Parsepp:

       XML::Reader utilise XML::Parser comme sous-module. Cette	configuration
       marche trA"s bien, sauf dans le cas oA^1	il n'y a pas de	compilateur C
       disponible pour installer XML::Parser. Dans ce cas, XML::Parsepp	peut
       remplacer XML::Parser.  Voici un	exemple:

	 use XML::Reader qw(XML::Parser);

	 my $text = q{<init>n <?test pi?> t<page node="400">m <!-- remark --> r</page></init>};

	 my $rdr = XML::Reader->new(\$text);
	 while ($rdr->iterate) {
	     printf "Path: %-19s, Value: %s\n",	$rdr->path, $rdr->value;
	 }

       La seule	chose est que XML::Reader dA(C)pend des	deux modules
       XML::Parser et XML::Parsepp. En consA(C)quence, si vous ne pouvez pas
       installer XML::Parser, vous pouvez quand	mAame installer	XML::Reader,
       mais vous ne lancez pas les tests.

DESCRIPTION
       XML::Reader est un module simple	et facile A  utiliser pour parser des
       fichiers	XML de maniA"re	sA(C)quentielle	(aussi appellA(C) parseur
       guidA(C)	par l'extraction) et, en mAame temps, il enregistre le chemin
       complet du XML.

       Il a A(C)tA(C) dA(C)veloppA(C) comme une	couche sur
       XML::Parser/XML::Parsepp	(quelques fonctionalitA(C)s basiques ont
       A(C)tA(C) copiA(C) de XML::TokeParser). XML::Parser, XML::Parsepp et
       XML::TokeParser utilisent chacun	une mA(C)thode d'extraction
       sA(C)quentielle,	mais ils n'enregistrent	pas le chemin du XML.

       De plus,	avec les interfaces de XML::Parser, XML::Parsepp et
       XML::TokeParser,	on est obligA(C) de sA(C)parer les balises de
       dA(C)but, les balises de	fin et du texte, ce qui, A  mon	avis, rend
       l'utilisation assez compliquA(C). (par contre, si on le souhaite,
       XML::Reader peut	agir d'une maniA"re A  ce que les balises de dA(C)but,
       les balises de fin et du	texte sont sA(C)parA(C)s, par l'option {filter
       => 4, mode => 'pyx'}).

       Il y a aussi XML::TiePYX, qui permet de parser des fichiers XML de
       maniA"re	sA(C)quentielle	(voir
       <http://www.xml.com/pub/a/2000/03/15/feature/index.html>	pour consulter
       une introduction	A  PYX).  Mais mAame avec XML::TiePYX, il faut
       sA(C)parer les balises de dA(C)but, les balises de fin et le texte, et
       il n'y a	pas de chemin disponible.

       Par contre, avec	XML::Reader, les les balises de	dA(C)but, les balises
       de fin et le texte sont traduits	en expressions similaires A  XPath. En
       consA(C)quence, il est inutile de compter des balises individuelles, on
       a un chemin et une valeur, et A<section>a suffit. (par contre, au cas
       oA^1 on veut opA(C)rer XML::Reader en fonctionnement compatible A  PYX,
       il y a toujours l'option	{filter	=> 4, mode => 'pyx'}, comme dA(C)jA
       mentionnA(C) ci-dessus).

       Mais revenons-nous au fonctionnement normal de XML::Reader, voici un
       exemple XML dans	la variable '$line1':

	 my $line1 =
	 q{<?xml version="1.0" encoding="iso-8859-1"?>
	   <data>
	     <item>abc</item>
	     <item><!--	c1 -->
	       <dummy/>
	       fgh
	       <inner name="ttt" id="fff">
		 ooo <!-- c2 --> ppp
	       </inner>
	     </item>
	   </data>
	 };

       Cet exemple peut	Aatre parsA(C) avec XML::Reader	en utilisant les
       mA(C)thodes "iterate" pour lire sA(C)quentiellement les donnA(C)es XML,
       et en utilisant les mA(C)thodes "path" et "value" pour extraire le
       chemin et la valeur A  un endroit prA(C)cis dans	le fichier XML.

       Si nA(C)cessaire, on peut A(C)galement identifier les balises
       individuelles de	dA(C)but et de fin: Il y a une mA(C)thode "is_start",
       qui donne 1 ou 0	(c'est A  dire:	1, s'il	y a une	balise de dA(C)but A
       la position actuelle, sinon 0).	Il y a A(C)galement la mA(C)thode
       A(C)quivalente "is_end".

       En plus,	il y a les mA(C)thodes "tag", "attr", "type" and "level".
       "tag" retourne le nom de	la balise en cours, "attr" retourne
       l'identifiant d'un attribut, "type" retourne 'T'	s'il y a du texte, ou
       '@' s'il	y a des	attributs et "level" indique le	niveau de cascadage
       (un nombre >= 0)

       Voici un	programme qui lit le XML dans la variable '$line1' (voir ci-
       dessus) pour montrer le principe...

	 use XML::Reader qw(XML::Parser);

	 my $rdr = XML::Reader->new(\$line1);
	 my $i = 0;
	 while ($rdr->iterate) { $i++;
	     printf "%3d. pat=%-22s, val=%-9s, s=%-1s, e=%-1s, tag=%-6s, atr=%-6s, t=%-1s, lvl=%2d\n", $i,
	       $rdr->path, $rdr->value,	$rdr->is_start,	$rdr->is_end, $rdr->tag, $rdr->attr, $rdr->type, $rdr->level;
	 }

       ...et voici le rA(C)sultat:

	  1. pat=/data		       , val=	      ,	s=1, e=0, tag=data  , atr=	, t=T, lvl= 1
	  2. pat=/data/item	       , val=abc      ,	s=1, e=1, tag=item  , atr=	, t=T, lvl= 2
	  3. pat=/data		       , val=	      ,	s=0, e=0, tag=data  , atr=	, t=T, lvl= 1
	  4. pat=/data/item	       , val=	      ,	s=1, e=0, tag=item  , atr=	, t=T, lvl= 2
	  5. pat=/data/item/dummy      , val=	      ,	s=1, e=1, tag=dummy , atr=	, t=T, lvl= 3
	  6. pat=/data/item	       , val=fgh      ,	s=0, e=0, tag=item  , atr=	, t=T, lvl= 2
	  7. pat=/data/item/inner/@id  , val=fff      ,	s=0, e=0, tag=@id   , atr=id	, t=@, lvl= 4
	  8. pat=/data/item/inner/@name, val=ttt      ,	s=0, e=0, tag=@name , atr=name	, t=@, lvl= 4
	  9. pat=/data/item/inner      , val=ooo ppp  ,	s=1, e=1, tag=inner , atr=	, t=T, lvl= 3
	 10. pat=/data/item	       , val=	      ,	s=0, e=1, tag=item  , atr=	, t=T, lvl= 2
	 11. pat=/data		       , val=	      ,	s=0, e=1, tag=data  , atr=	, t=T, lvl= 1

INTERFACE
   Cr~A(C)ation objet
       Pour crA(C)er un	objet, on utilise la syntaxe suivante:

	 my $rdr = XML::Reader->new($data,
	   {strip => 1,	filter => 2, using => ['/path1', '/path2']});

       L'A(C)lA(C)ment $data est obligatoire, il est le	nom d'un fichier XML,
       ou une URL qui commence par 'http://...', ou la rA(C)fA(C)rence A  une
       chaA(R)ne de caractA"res, dans ce cas le	contenu	de cette chaA(R)ne de
       caractA"res est acceptA(C) comme	XML.

       Sinon, $data peut A(C)galement Aatre une	rA(C)fA(C)rence	A  un fichier,
       comme par exemple \*STDIN. Dans ce cas, la rA(C)fA(C)rence de fichier
       est utiliser pour lire le XML.

       Voici un	exemple	pour crA(C)er un objet XML::Reader avec	un fichier:

	 my $rdr = XML::Reader->new('input.xml');

       Voici un	autre exemple pour crA(C)er un objet XML::Reader avec une
       rA(C)fA(C)rence A  une chaA(R)ne	de caractA"res:

	 my $rdr = XML::Reader->new(\'<data>abc</data>');

       Voici un	exemple	pour crA(C)er un objet XML::Reader avec	une
       rA(C)fA(C)rence A  un fichier:

	 open my $fh, '<', 'input.xml' or die "Error: $!";
	 my $rdr = XML::Reader->new($fh);

       Voici un	exemple	pour crA(C)er un objet XML::Reader avec	\*STDIN:

	 my $rdr = XML::Reader->new(\*STDIN);

       On peut ajouter une ou plusieurs	options	dans une rA(C)fA(C)rence A  un
       hashage:

       option {parse_ct	=> }
	   Option {parse_ct => 1} permet de lire les commentaires, le defaut
	   est {parse_ct => 0}

       option {parse_pi	=> }
	   Option {parse_pi => 1} permet de lire les processing-instructions
	   et les XML-declarations, le dA(C)faut est {parse_pi => 0}

       option {using =>	}
	   Option {using => } permet de	sA(C)lectionner	un arbre prA(C)cis
	   dans	le XML.

	   La syntaxe est {using => ['/path1/path2/path3',
	   '/path4/path5/path6']}

       option {filter => } et {mode => }
	   Option {filter => 2}	ou {mode => 'attr-bef-start'} affiche tous les
	   A(C)lA(C)ments, y compris les attributs.

	   Option {filter => 3}	ou {mode => 'attr-in-hash'} supprime les
	   attributs (c'est A  dire il supprime	toutes les lignes qui sont
	   $rdr->type eq '@'). En revanche, le contenu des attributs sont
	   retournA(C) dans le hashage $rdr->att_hash.

	   Option {filter => 4}	ou {mode => 'pyx'} crA(C)e une ligne
	   individuel pour chaque balise de dA(C)but, de fin, pour chaque
	   attribut, pour chaque commentaire et	pour chaque processing-
	   instruction.	Ce fonctionnement permet, en effet, de gA(C)nA(C)rer
	   un format PYX.

	   Option {filter => 5}	ou {mode => 'branches'}	selectionne uniquement
	   les donnA(C)es pour les racines ("root"). Les A(C)lA(C)ments	pour
	   chaque "root" sont accumulA(C) dans une rA(C)fA(C)rence A  un array
	   (comme specifiA(C) dans la partie "branch") et quand	le "branch"
	   est complet,	les donnA(C)es sont retournA(C). Cette procA(C)dure se
	   trouve au milieu entre l'option "using" (qui	retourne les
	   A(C)lA(C)ments un par un) et	la fonction "slurp_xml"	(qui accumule
	   les donnA(C)es dans un "branch", et tous les	"branches" sont
	   accumulA(C)s	dans une seule structure en mA(C)moire).

	   La syntaxe est {filter => 2|3|4|5, mode =>
	   'attr-bef-start'|'attr-in-hash'|'pyx'|'branches'}, le dA(C)faut est
	   {filter => 2, mode => 'attr-bef-start'}

       option {strip =>	}
	   Option {strip => 1} supprime	les caractA"res	blancs au dA(C)but et
	   A  la fin d'un texte	ou d'un	commentaire.  (les caractA"res blancs
	   d'un	attribut ne sont jamais	supprimA(C)). L'option {strip => 0}
	   laisse le texte ou commentaire intacte.

	   La syntaxe est {strip => 0|1}, le dA(C)faut est {strip => 1}

       option {dupatt => }
	   L'option {dupatt => '*'} permet de lire plusieurs attributs avec le
	   mAame nom. Les diffA(C)rentes valeurs sont donc concatenA(C)es par
	   '*'.

   M~A(C)thodes
       Un objet	du type	XML::Reader a des mA(C)thodes suivantes:

       iterate
	   La mA(C)thode "iterate" lit un A(C)lA(C)ment	XML. Elle retourne 1,
	   si la lecture a A(C)tA(C) un	succA"s, ou undef A  la	fin du fichier
	   XML.

       path
	   La mA(C)thode "path"	retourne le chemin complet de la ligne en
	   cours, les attributs	sont rA(C)prA(C)sentA(C)s avec des caractA"res
	   '@'.

       value
	   La mA(C)thode "value" retourne la valeur de la ligne	en cours
	   (c'est A  dire le texte ou l'attribut).

	   Conseil: en cas de {filter => 2 ou 3} avec une dA(C)claration-XML
	   (c'est A  dire $rdr->is_decl	== 1), il vaut mieux ne	pas prendre
	   compte de la	valeur (elle sera vide,	de toute faA<section>on). Un
	   bout	de programme:

	     print $rdr->value,	"\n" unless $rdr->is_decl;

	   Le programme	ci-dessus ne s'applique	*pas* A	 {filter => 4},	dans
	   ce cas un simple "print $rdr->value;" est suffisant:

	     print $rdr->value,	"\n";

       comment
	   La mA(C)thode "comment" retourne le commentaire d'un	fichier	XML.
	   Il est conseillA(C) de tester $rdr->is_comment avant	d'accA(C)der
	   A  la mA(C)thode "comment".

       type
	   La mA(C)thode "type"	retourne 'T' quand il y	a du texte dans	le
	   XML,	et '@' quand il	y a un attribut.

	   Si l'option {filter => 4} est active, les possibilitA(C)s sont: 'T'
	   pour	du texte, '@' poir un attribut,	'S' pour une balise de
	   dA(C)but, 'E' pour une balise de fin, '#' pour un commentaire, 'D'
	   pour	une dA(C)claration-XML,	'?' pour une processing-instruction.

       tag La mA(C)thode "tag" retourne	le nom de la balise en cours.

       attr
	   La mA(C)thode "attr"	retourne le nom	de l'attribut en cours (elle
	   retourne une	chaA(R)ne de caractA"res vide si l'A(C)lA(C)ment en
	   cours n'est pas un attribut)

       level
	   La mA(C)thode "level" retourne le niveau de cascadage (un nombre >
	   0)

       prefix
	   La mA(C)thode "prefix" retourne le prA(C)fixe du chemin (c'est la
	   partie du chemin qui	a A(C)tA(C) supprimA(C)	dans l'option {using
	   => ...}). Elle retourne une chaA(R)ne de caractA"res	vide au	cas
	   oA^1	l'option {using	=> ...}	n'a pas	A(C)tA(C) specifiA(C)e.

       att_hash
	   La mA(C)thode "att_hash" retourne une rA(C)fA(C)rence A  l'hachage
	   des attributs de la balise de dA(C)but en cours (au cas oA^1
	   l'A(C)lA(C)ment en cours n'est pas une balise de dA(C)but, un
	   hachage vide	est retournA(C))

       dec_hash
	   La mA(C)thode "dec_hash" retourne une rA(C)fA(C)rence A  l'hachage
	   des attributs de la XML-declaration en cours	(au cas	oA^1
	   l'A(C)lA(C)ment en cours n'est pas une XML-declaration, un hachage
	   vide	est retournA(C))

       proc_tgt
	   La mA(C)thode "proc_tgt" retourne la	partie cible (c'est A  dire la
	   premiA"re partie) de	la processing-instruction (au cas oA^1
	   l'A(C)lA(C)ment en cours n'est pas une processing-instruction, une
	   chaA(R)ne de	caractA"res vide est retournA(C))

       proc_data
	   La mA(C)thode "proc_data" retourne la partie	donnA(C)e (c'est A
	   dire	la deuxiA"me partie) de	la processing-instruction (au cas oA^1
	   l'A(C)lA(C)ment en cours n'est pas une processing-instruction, une
	   chaA(R)ne de	caractA"res vide est retournA(C))

       pyx La mA(C)thode "pyx" retourne	la chaA(R)ne de	caractA"res format
	   "PYX" de l'A(C)lA(C)ment XML	en cours.

	   La chaA(R)ne	de caractA"res format "PYX" est	une chaA(R)ne de
	   caractA"res avec un premier caractA"re spA(C)cifique. Ce premier
	   caractA"re de chaque	ligne "PYX" dA(C)termine le type: si le
	   premier caractA"re est un '(', alors	A<section>a signifie une
	   balise de dA(C)but. Si le premier caractA"re	est un ')', alors
	   A<section>a signifie	une balise de fin. Si le premier caractA"re
	   est un 'A', alors A<section>a signifie un attribut. Si le premier
	   caractA"re est un '-', alors	A<section>a signifie un	texte. Si le
	   premier caractA"re est un '?', alors	A<section>a signifie une
	   processing-instruction. (voir
	   <http://www.xml.com/pub/a/2000/03/15/feature/index.html> pour une
	   introduction	A  PYX)

	   La mA(C)thode "pyx" n'est utile que pour l'option {filter =>	4},
	   sinon, pour un {filter => } diffA(C)rent de 4, on retourne undef.

       is_start
	   La mA(C)thode "is_start" retourne 1,	si l'A(C)lA(C)ment en cours
	   est une balise de dA(C)but, sinon 0 est retournA(C).

       is_end
	   La mA(C)thode "is_end" retourne 1, si l'A(C)lA(C)ment en cours est
	   une balise de fin, sinon 0 est retournA(C).

       is_decl
	   La mA(C)thode "is_decl" retourne 1, si l'A(C)lA(C)ment en cours est
	   une XML-declaration,	sinon 0	est retournA(C).

       is_proc
	   La mA(C)thode "is_proc" retourne 1, si l'A(C)lA(C)ment en cours est
	   une processing-instruction, sinon 0 est retournA(C).

       is_comment
	   La mA(C)thode "is_comment" retourne 1, si l'A(C)lA(C)ment en	cours
	   est un commentaire, sinon 0 est retournA(C).

       is_text
	   La mA(C)thode "is_text" retourne 1, si l'A(C)lA(C)ment en cours est
	   un texte, sinon 0 est retournA(C).

       is_attr
	   La mA(C)thode "is_attr" retourne 1, si l'A(C)lA(C)ment en cours est
	   un attribut,	sinon 0	est retournA(C).

       is_value
	   La mA(C)thode "is_attr" retourne 1, si l'A(C)lA(C)ment en cours est
	   un texte ou un attribut, sinon 0 est	retournA(C). Cette mA(C)thode
	   est plutA't utile pour l'option {filter => 4, mode => 'pyx'}, oA^1
	   on peut tester l'utilitA(C) de la mA(C)thode	"value".

       rx  C'est l'indexe de la	branche	en cours (cette	fonction est valide
	   uniquement avec {filter => 5}).

       rvalue
	   C'est une rA(C)fA(C)rence A	une valeur scalaire (ou	A  une liste)
	   de la branche en cours (cette fonction est valide uniquement	avec
	   {filter => 5}). rvalue est plus rapide, mais	moins simple A
	   utiliser que	la fonction value (avec	rvalue vous devez faire	votre
	   dA(C)rA(C)fA(C)rencement vous mAame).

       rstem
	   Cette fonction est identique	A  la fonction "path"

OPTION USING
       L'option	{using => ...} permet de sA(C)lectionner un sous-arbre du XML.

       Voici comment A<section>a fonctionne en dA(C)tail...

       L'option	{using => ['/chemin1/chemin2/chemin3',
       '/chemin4/chemin5/chemin6']} d'abord elimine toutes les lignes oA^1 le
       chemin ne commence pas avec '/chemin1/chemin2/chemin3' ou
       '/chemin4/chemin5/chemin6'.

       Les lignes restantes (ceux qui n'ont pas	A(C)tA(C) eliminA(C)) ont un
       chemin plus court. En fait le prA(C)fixe	'/chemin1/chemin2/chemin3' (ou
       '/chemin4/chemin5/chemin6') a A(C)tA(C) supprimA(C). En revanche, ce
       prA(C)fixe supprimA(C) apparaA(R)t dans la mA(C)thode "prefix".

       On dit que '/chemin1/chemin2/chemin3' (ou '/chemin4/chemin5/chemin6')
       sont "absolu" et	"complA"t". Le mot "absolu" signifie que chaque	chemin
       commence	forcement par un caractA"re '/', et le mot "complA"t" signifie
       que la derniA"re	partie 'chemin3' (ou 'chemin6')	sera suivi
       implicitement par un caractA"re '/'.

   Exemple avec	using
       Le programme suivant prend un fichier XML et le parse avec XML::Reader,
       y compris l'option 'using' pour cibler des A(C)lA(C)ments
       spA(C)cifiques:

	 use XML::Reader qw(XML::Parser);

	 my $line2 = q{
	 <data>
	   <order>
	     <database>
	       <customer name="aaa" />
	       <customer name="bbb" />
	       <customer name="ccc" />
	       <customer name="ddd" />
	     </database>
	   </order>
	   <dummy value="ttt">test</dummy>
	   <supplier>hhh</supplier>
	   <supplier>iii</supplier>
	   <supplier>jjj</supplier>
	 </data>
	 };

	 my $rdr = XML::Reader->new(\$line2,
	   {using => ['/data/order/database/customer', '/data/supplier']});

	 my $i = 0;
	 while ($rdr->iterate) { $i++;
	     printf "%3d. prf=%-29s, pat=%-7s, val=%-3s, tag=%-6s, t=%-1s, lvl=%2d\n",
	       $i, $rdr->prefix, $rdr->path, $rdr->value, $rdr->tag, $rdr->type, $rdr->level;
	 }

       Voici le	rA(C)sultat de ce programme:

	  1. prf=/data/order/database/customer,	pat=/@name , val=aaa, tag=@name	, t=@, lvl= 1
	  2. prf=/data/order/database/customer,	pat=/	   , val=   , tag=	, t=T, lvl= 0
	  3. prf=/data/order/database/customer,	pat=/@name , val=bbb, tag=@name	, t=@, lvl= 1
	  4. prf=/data/order/database/customer,	pat=/	   , val=   , tag=	, t=T, lvl= 0
	  5. prf=/data/order/database/customer,	pat=/@name , val=ccc, tag=@name	, t=@, lvl= 1
	  6. prf=/data/order/database/customer,	pat=/	   , val=   , tag=	, t=T, lvl= 0
	  7. prf=/data/order/database/customer,	pat=/@name , val=ddd, tag=@name	, t=@, lvl= 1
	  8. prf=/data/order/database/customer,	pat=/	   , val=   , tag=	, t=T, lvl= 0
	  9. prf=/data/supplier		      ,	pat=/	   , val=hhh, tag=	, t=T, lvl= 0
	 10. prf=/data/supplier		      ,	pat=/	   , val=iii, tag=	, t=T, lvl= 0
	 11. prf=/data/supplier		      ,	pat=/	   , val=jjj, tag=	, t=T, lvl= 0

   Exemple sans	using
       Le programme suivant prend un fichier XML et le parse avec XML::Reader,
       mais sans option	'using':

	 use XML::Reader qw(XML::Parser);

	 my $rdr = XML::Reader->new(\$line2);
	 my $i = 0;
	 while ($rdr->iterate) { $i++;
	     printf "%3d. prf=%-1s, pat=%-37s, val=%-6s, tag=%-11s, t=%-1s, lvl=%2d\n",
	      $i, $rdr->prefix,	$rdr->path, $rdr->value, $rdr->tag, $rdr->type,	$rdr->level;
	 }

       Comme on	peut constater dans le rA(C)sultat suivant, il y a beaucoup
       plus de lignes, le prA(C)fixe est vide et le chemin est beaucoup	plus
       longue par rapport au programme prA(C)cA(C)dent:

	  1. prf= , pat=/data				     , val=	 , tag=data	  , t=T, lvl= 1
	  2. prf= , pat=/data/order			     , val=	 , tag=order	  , t=T, lvl= 2
	  3. prf= , pat=/data/order/database		     , val=	 , tag=database	  , t=T, lvl= 3
	  4. prf= , pat=/data/order/database/customer/@name  , val=aaa	 , tag=@name	  , t=@, lvl= 5
	  5. prf= , pat=/data/order/database/customer	     , val=	 , tag=customer	  , t=T, lvl= 4
	  6. prf= , pat=/data/order/database		     , val=	 , tag=database	  , t=T, lvl= 3
	  7. prf= , pat=/data/order/database/customer/@name  , val=bbb	 , tag=@name	  , t=@, lvl= 5
	  8. prf= , pat=/data/order/database/customer	     , val=	 , tag=customer	  , t=T, lvl= 4
	  9. prf= , pat=/data/order/database		     , val=	 , tag=database	  , t=T, lvl= 3
	 10. prf= , pat=/data/order/database/customer/@name  , val=ccc	 , tag=@name	  , t=@, lvl= 5
	 11. prf= , pat=/data/order/database/customer	     , val=	 , tag=customer	  , t=T, lvl= 4
	 12. prf= , pat=/data/order/database		     , val=	 , tag=database	  , t=T, lvl= 3
	 13. prf= , pat=/data/order/database/customer/@name  , val=ddd	 , tag=@name	  , t=@, lvl= 5
	 14. prf= , pat=/data/order/database/customer	     , val=	 , tag=customer	  , t=T, lvl= 4
	 15. prf= , pat=/data/order/database		     , val=	 , tag=database	  , t=T, lvl= 3
	 16. prf= , pat=/data/order			     , val=	 , tag=order	  , t=T, lvl= 2
	 17. prf= , pat=/data				     , val=	 , tag=data	  , t=T, lvl= 1
	 18. prf= , pat=/data/dummy/@value		     , val=ttt	 , tag=@value	  , t=@, lvl= 3
	 19. prf= , pat=/data/dummy			     , val=test	 , tag=dummy	  , t=T, lvl= 2
	 20. prf= , pat=/data				     , val=	 , tag=data	  , t=T, lvl= 1
	 21. prf= , pat=/data/supplier			     , val=hhh	 , tag=supplier	  , t=T, lvl= 2
	 22. prf= , pat=/data				     , val=	 , tag=data	  , t=T, lvl= 1
	 23. prf= , pat=/data/supplier			     , val=iii	 , tag=supplier	  , t=T, lvl= 2
	 24. prf= , pat=/data				     , val=	 , tag=data	  , t=T, lvl= 1
	 25. prf= , pat=/data/supplier			     , val=jjj	 , tag=supplier	  , t=T, lvl= 2
	 26. prf= , pat=/data				     , val=	 , tag=data	  , t=T, lvl= 1

OPTION PARSE_CT
       L'option	{parse_ct => 1}	permet de parser les commentaires
       (normalement, les commentaires ne sont pas pris en compte par
       XML::Reader, le dA(C)faut est {parse_ct => 0}.

       Voici un	exemple	oA^1 les commentaires ne sont pas pris en compte par
       dA(C)faut:

	 use XML::Reader qw(XML::Parser);

	 my $text = q{<?xml version="1.0"?><dummy>xyz <!-- remark --> stu <?ab cde?> test</dummy>};

	 my $rdr = XML::Reader->new(\$text);

	 while ($rdr->iterate) {
	     if	($rdr->is_decl)	   { my	%h = %{$rdr->dec_hash};
				     print "Found decl	   ",  join('',	map{" $_='$h{$_}'"} sort keys %h), "\n"; }
	     if	($rdr->is_proc)	   { print "Found proc	    ", "t=", $rdr->proc_tgt, ",	d=", $rdr->proc_data, "\n"; }
	     if	($rdr->is_comment) { print "Found comment   ", $rdr->comment, "\n"; }
	     print "Text '", $rdr->value, "'\n"	unless $rdr->is_decl;
	 }

       Voici le	rA(C)sultat:

	 Text 'xyz stu test'

       Ensuite,	les mAames donnA(C)es XML et le	mAame algorithme, sauf
       l'option	{parse_ct => 1}, qui est maintenant active:

	 use XML::Reader qw(XML::Parser);

	 my $text = q{<?xml version="1.0"?><dummy>xyz <!-- remark --> stu <?ab cde?> test</dummy>};

	 my $rdr = XML::Reader->new(\$text, {parse_ct => 1});

	 while ($rdr->iterate) {
	     if	($rdr->is_decl)	   { my	%h = %{$rdr->dec_hash};
				     print "Found decl	   ",  join('',	map{" $_='$h{$_}'"} sort keys %h), "\n"; }
	     if	($rdr->is_proc)	   { print "Found proc	    ", "t=", $rdr->proc_tgt, ",	d=", $rdr->proc_data, "\n"; }
	     if	($rdr->is_comment) { print "Found comment   ", $rdr->comment, "\n"; }
	     print "Text '", $rdr->value, "'\n"	unless $rdr->is_decl;
	 }

       Voici le	rA(C)sultat:

	 Text 'xyz'
	 Found comment	 remark
	 Text 'stu test'

OPTION PARSE_PI
       L'option	{parse_pi => 1}	permet de parser les processing-instructions
       et les XML-Declarations (normalement, ni	les processing-instructions,
       ni les XML-Declarations ne sont pris en compte par XML::Reader, le
       dA(C)faut est {parse_pi => 0}.

       Comme exemple, on prend exactement les mAames donnA(C)es	XML et le
       mAame algorithme	du paragraphe prA(C)cA(C)dent, sauf l'option {parse_pi
       => 1}, qui est maintenant active	(avec l'option {parse_ct => 1}):

	 use XML::Reader qw(XML::Parser);

	 my $text = q{<?xml version="1.0"?><dummy>xyz <!-- remark --> stu <?ab cde?> test</dummy>};

	 my $rdr = XML::Reader->new(\$text, {parse_ct => 1, parse_pi =>	1});

	 while ($rdr->iterate) {
	     if	($rdr->is_decl)	   { my	%h = %{$rdr->dec_hash};
				     print "Found decl	   ",  join('',	map{" $_='$h{$_}'"} sort keys %h), "\n"; }
	     if	($rdr->is_proc)	   { print "Found proc	    ", "t=", $rdr->proc_tgt, ",	d=", $rdr->proc_data, "\n"; }
	     if	($rdr->is_comment) { print "Found comment   ", $rdr->comment, "\n"; }
	     print "Text '", $rdr->value, "'\n"	unless $rdr->is_decl;
	 }

       Notez le	"unless	$rdr->is_decl" dans le programme ci-dessus. C'est pour
       A(C)viter le texte vide aprA"s la XML-dA(C)claration.

       Voici le	rA(C)sultat:

	 Found decl	 version='1.0'
	 Text 'xyz'
	 Found comment	 remark
	 Text 'stu'
	 Found proc	 t=ab, d=cde
	 Text 'test'

OPTION FILTER /	MODE
       L'option	{filter	=> } ou	{mode => } permet de sA(C)lectionner des
       diffA(C)rents modes d'opA(C)ratoires pour le traitement du XML.

   Option filter 2 mode	attr-bef-start
       Avec l'option {filter =>	2} ou {mode => 'attr-bef-start'}, XML::Reader
       gA(C)nA"re une ligne pour chaque	morceau	de texte. Si la	balise
       prA(C)cA(C)dente	est une	balise de dA(C)but, alors la mA(C)tode
       "is_start" retourne 1. Si la balise suivante est	une balise de fin,
       alors la	mA(C)tode "is_end" retourne 1. Si la balise prA(C)cA(C)dente
       est une balise de commentaire, alors la mA(C)thode "is_comment"
       retourne	1. Si la balise	prA(C)cA(C)dente est une balise	de XML-
       declaration, alors la mA(C)thode	"is_decl" retourne 1. Si la balise
       prA(C)cA(C)dente	est une	balise de processing-instruction, alors	la
       mA(C)thode "is_decl" retourne 1.

       De plus,	les attributs sont reprA(C)sentA(C)s par des lignes
       supplA(C)mentaires avec la syntaxe '/@...'.

       Option {filter => 2, mode => 'attr-bef-start'} est le dA(C)faut.

       Voici un	exemple...

	 use XML::Reader qw(XML::Parser);

	 my $text = q{<root><test param='&lt;&gt;v"'><a><b>"e"<data id="&lt;&gt;z'">'g'&amp;&lt;&gt;</data>}.
		    q{f</b></a></test>x	<!-- remark -->	yz</root>};

	 my $rdr = XML::Reader->new(\$text);

	 # les quatres alternatives ci-dessous sont equivalent:
	 # ----------------------------------------------------
	 #   XML::Reader->new(\$text);
	 #   XML::Reader->new(\$text, {filter => 2			    });
	 #   XML::Reader->new(\$text, {filter => 2, mode => 'attr-bef-start'});
	 #   XML::Reader->new(\$text, {		    mode => 'attr-bef-start'});

	 while ($rdr->iterate) {
	     printf "Path: %-24s, Value: %s\n",	$rdr->path, $rdr->value;
	 }

       Le programme (avec l'option {filter => 2, mode => 'attr-bef-start'}
       implicitement par dA(C)faut) gA(C)nA"re le rA(C)sultat suivant:

	 Path: /root		       , Value:
	 Path: /root/test/@param       , Value:	<>v"
	 Path: /root/test	       , Value:
	 Path: /root/test/a	       , Value:
	 Path: /root/test/a/b	       , Value:	"e"
	 Path: /root/test/a/b/data/@id , Value:	<>z'
	 Path: /root/test/a/b/data     , Value:	'g'&<>
	 Path: /root/test/a/b	       , Value:	f
	 Path: /root/test/a	       , Value:
	 Path: /root/test	       , Value:
	 Path: /root		       , Value:	x yz

       L'option	(implicite) {filter => 2, mode => 'attr-bef-start'} permet
       A(C)galement de reconstruire la structure du XML	avec l'assistance des
       mA(C)thodes "is_start" and "is_end". Notez que dans le rA(C)sultat ci-
       dessus, la premiA"re ligne ("Path: /root, Value:") est vide, mais elle
       est importante pour la structure	du XML.

       Prenons-nous le mAame exemple {filter =>	2, mode	=> 'attr-bef-start'}
       avec un algorithme pour reconstruire la structure originale du XML. En
       plus, on	exige de rajouter des caractA"res "** **" pour chaque texte
       (mais pas les balises et	pas non	plus les attributs):

	 use XML::Reader qw(XML::Parser);

	 my $text = q{<root><test param='&lt;&gt;v"'><a><b>"e"<data id="&lt;&gt;z'">'g'&amp;&lt;&gt;</data>}.
		    q{f</b></a></test>x	<!-- remark -->	yz</root>};

	 my $rdr = XML::Reader->new(\$text);

	 # les quatres alternatives ci-dessous sont equivalent:
	 # ----------------------------------------------------
	 #   XML::Reader->new(\$text);
	 #   XML::Reader->new(\$text, {filter => 2			    });
	 #   XML::Reader->new(\$text, {filter => 2, mode => 'attr-bef-start'});
	 #   XML::Reader->new(\$text, {		    mode => 'attr-bef-start'});

	 my %at;

	 while ($rdr->iterate) {
	     my	$indentation = '  ' x ($rdr->level - 1);

	     if	($rdr->type eq '@')  {
		 $at{$rdr->attr} = $rdr->value;
		 for ($at{$rdr->attr}) {
		     s{&}'&amp;'xmsg;
		     s{'}'&apos;'xmsg;
		     s{<}'&lt;'xmsg;
		     s{>}'&gt;'xmsg;
		 }
	     }

	     if	($rdr->is_start) {
		 print $indentation, '<', $rdr->tag, join('', map{" $_='$at{$_}'"} sort	keys %at), '>',	"\n";
	     }

	     unless ($rdr->type	eq '@')	{ %at =	(); }

	     if	($rdr->type eq 'T' and $rdr->value ne '') {
		 my $v = $rdr->value;
		 for ($v) {
		     s{&}'&amp;'xmsg;
		     s{<}'&lt;'xmsg;
		     s{>}'&gt;'xmsg;
		 }
		 print $indentation, "	** $v **\n";
	     }

	     if	($rdr->is_end) {
		 print $indentation, '</', $rdr->tag, '>', "\n";
	     }
	 }

       ...voici	le rA(C)sultat:

	 <root>
	   <test param='&lt;&gt;v"'>
	     <a>
	       <b>
		 ** "e"	**
		 <data id='&lt;&gt;z&apos;'>
		   ** 'g'&amp;&lt;&gt; **
		 </data>
		 ** f **
	       </b>
	     </a>
	   </test>
	   ** x	yz **
	 </root>

       ...ce qui donne preuve que la structure originale du XML	n'est pas
       perdu.

   Option filter 3 mode	attr-in-hash
       Pour la plupart,	l'option {filter => 3, mode => 'attr-in-hash'}
       fonctionne comme	l'option {filter => 2, mode => 'attr-bef-start'}.

       Mais il y a une diffA(C)rence: avec l'option {filter => 3, mode =>
       'attr-in-hash'},	les attributs sont supprimA(C)es et A  la place, les
       attributs sont prA(C)sentA(C)s dans un hashage "$rdr->"att_hash"()"
       pour chaque balise de dA(C)but.

       Ainsi, dans l'algorithme	prA(C)cA(C)dent, on peut supprimer la variable
       globale "%at" et	la remplacer par %{$rdr->"att_hash"}:

       Voici un	nouveau	algorithme avec	{filter	=> 3, mode => 'attr-in-hash'},
       on ne s'occupe pas des attributs	(c'est-A -dire,	on ne verifie pas
       $rdr->type eq '@') et (comme dA'jA  mentionnA(C)	ci-dessus) la variable
       %at est remplacA(C)e par	%{$rdr->att_hash} :

	 use XML::Reader qw(XML::Parser);

	 my $text = q{<root><test param='&lt;&gt;v"'><a><b>"e"<data id="&lt;&gt;z'">'g'&amp;&lt;&gt;</data>}.
		    q{f</b></a></test>x	<!-- remark -->	yz</root>};

	 my $rdr = XML::Reader->new(\$text, {filter => 3});

	 # les trois alternatives ci-dessous sont equivalent:
	 # --------------------------------------------------
	 #   XML::Reader->new(\$text, {filter => 3			  });
	 #   XML::Reader->new(\$text, {filter => 3, mode => 'attr-in-hash'});
	 #   XML::Reader->new(\$text, {		    mode => 'attr-in-hash'});

	 while ($rdr->iterate) {
	     my	$indentation = '  ' x ($rdr->level - 1);

	     if	($rdr->is_start) {
		 my %h = %{$rdr->att_hash};
		 for (values %h) {
		     s{&}'&amp;'xmsg;
		     s{'}'&apos;'xmsg;
		     s{<}'&lt;'xmsg;
		     s{>}'&gt;'xmsg;
		 }
		 print $indentation, '<', $rdr->tag,
		   join('', map{" $_='$h{$_}'"}	sort keys %h),
		   '>',	"\n";
	     }

	     if	($rdr->type eq 'T' and $rdr->value ne '') {
		 my $v = $rdr->value;
		 for ($v) {
		     s{&}'&amp;'xmsg;
		     s{<}'&lt;'xmsg;
		     s{>}'&gt;'xmsg;
		 }
		 print $indentation, "	** $v **\n";
	     }

	     if	($rdr->is_end) {
		 print $indentation, '</', $rdr->tag, '>', "\n";
	     }
	 }

       ...le rA(C)sultat de {filter => 3, mode => 'attr-in-hash'} est
       identique au rA(C)sultat	de {filter => 2, mode => 'attr-bef-start'}:

	 <root>
	   <test param='&lt;&gt;v"'>
	     <a>
	       <b>
		 ** "e"	**
		 <data id='&lt;&gt;z&apos;'>
		   ** 'g'&amp;&lt;&gt; **
		 </data>
		 ** f **
	       </b>
	     </a>
	   </test>
	   ** x	yz **
	 </root>

       Finalement on pourrait (et on devrait) effectuer	l'A(C)criture XML par
       un autre	module.	Je propose d'utiliser le module	XML::MinWriter.	Voici
       un programme qui	utilise	XML::MinWriter pour A(C)crire du XML:

	 use XML::Reader qw(XML::Parser);
	 use XML::MinWriter;

	 my $text = q{<root><test param='&lt;&gt;v"'><a><b>"e"<data id="&lt;&gt;z'">'g'&amp;&lt;&gt;</data>}.
		    q{f</b></a></test>x	<!-- remark -->	yz</root>};

	 my $rdr = XML::Reader->new(\$text, {filter => 3});
	 my $wrt = XML::MinWriter->new(OUTPUT => \*STDOUT, NEWLINES => 1);

	 while ($rdr->iterate) {
	     if	($rdr->is_start)			  { $wrt->startTag($rdr->tag, %{$rdr->att_hash}); }
	     if	($rdr->type eq 'T' and $rdr->value ne '') { $wrt->characters('** '.$rdr->value.' **'); }
	     if	($rdr->is_end)				  { $wrt->endTag($rdr->tag); }
	 }

	 $wrt->end();

       Voici le	rA(C)sultat de XML::MinWriter:

	 <root
	 ><test	param="&lt;&gt;v&quot;"
	 ><a
	 ><b
	 >** "e" **<data id="&lt;&gt;z'"
	 >** 'g'&amp;&lt;&gt; **</data
	 >** f **</b
	 ></a
	 ></test
	 >** x yz **</root
	 >

       A la premiA"re lecture, le format est bizarre, mais c'est du XML	tout
       A  fait correct.

   Option filter 4 mode	pyx
       MAame si	ce n'est pas la	raison principale de XML::Reader, l'option
       {filter => 4, mode => 'pyx'} permet de gA(C)nA(C)rer des	lignes
       individuelles pour chaque balise	de dA(C)but, de	fin, commentaires,
       processing-instruction et XML-Declaration.  Le but est de gA(C)nA(C)rer
       une chaA(R)ne de	caractA"res du modA"le "PYX" pour l'analyse par	la
       suite.

       Voici un	exemple:

	 use XML::Reader qw(XML::Parser);

	 my $text = q{<?xml version="1.0" encoding="iso-8859-1"?>
	   <delta>
	     <dim alter="511">
	       <gamma />
	       <beta>
		 car <?tt dat?>
	       </beta>
	     </dim>
	     dskjfh <!-- remark	--> uuu
	   </delta>};

	 my $rdr = XML::Reader->new(\$text, {filter => 4, parse_pi => 1});

	 # les trois alternatives ci-dessous sont equivalent:
	 # --------------------------------------------------
	 #   XML::Reader->new(\$text, {filter => 4		 , parse_pi => 1});
	 #   XML::Reader->new(\$text, {filter => 4, mode => 'pyx', parse_pi => 1});
	 #   XML::Reader->new(\$text, {		    mode => 'pyx', parse_pi => 1});

	 while ($rdr->iterate) {
	     printf "Type = %1s, pyx = %s\n", $rdr->type, $rdr->pyx;
	 }

       et voici	le rA(C)sultat:

	 Type =	D, pyx = ?xml version='1.0' encoding='iso-8859-1'
	 Type =	S, pyx = (delta
	 Type =	S, pyx = (dim
	 Type =	@, pyx = Aalter	511
	 Type =	S, pyx = (gamma
	 Type =	E, pyx = )gamma
	 Type =	S, pyx = (beta
	 Type =	T, pyx = -car
	 Type =	?, pyx = ?tt dat
	 Type =	E, pyx = )beta
	 Type =	E, pyx = )dim
	 Type =	T, pyx = -dskjfh uuu
	 Type =	E, pyx = )delta

       Il faut dire que	les commentaires, qui sont gA(C)nA(C)rA(C)s avec
       l'option	{parse_ct => 1}, ne font pas partie du standard	"PYX".	En
       fait, les commentaires sont gA(C)nA(C)rA(C)s avec un caractA"re '#' qui
       n'existe	pas dans le standard. Voici un exemple:

	 use XML::Reader qw(XML::Parser);

	 my $text = q{
	   <delta>
	     <!-- remark -->
	   </delta>};

	 my $rdr = XML::Reader->new(\$text, {filter => 4, parse_ct => 1});

	 # les trois alternatives ci-dessous sont equivalent:
	 # --------------------------------------------------
	 #   XML::Reader->new(\$text, {filter => 4,		   parse_ct => 1});
	 #   XML::Reader->new(\$text, {filter => 4, mode => 'pyx', parse_ct => 1});
	 #   XML::Reader->new(\$text, {		    mode => 'pyx', parse_ct => 1});

	 while ($rdr->iterate) {
	     printf "Type = %1s, pyx = %s\n", $rdr->type, $rdr->pyx;
	 }

       Voici le	rA(C)sultat:

	 Type =	S, pyx = (delta
	 Type =	#, pyx = #remark
	 Type =	E, pyx = )delta

       Avec l'option {filter =>	4, mode	=> 'pyx'}, les mA(C)thodes habituelles
       restent accessibles: "value", "attr", "path", "is_start", "is_end",
       "is_decl", "is_proc", "is_comment", "is_attr", "is_text", "is_value",
       "comment", "proc_tgt", "proc_data", "dec_hash" or "att_hash". Voici un
       exemple:

	 use XML::Reader qw(XML::Parser);

	 my $text = q{<?xml version="1.0"?>
	   <parent abc="def"> <?pt hmf?>
	     dskjfh <!-- remark	-->
	     <child>ghi</child>
	   </parent>};

	 my $rdr = XML::Reader->new(\$text, {filter => 4, parse_pi => 1, parse_ct => 1});

	 # les trois alternatives ci-dessous sont equivalent:
	 # --------------------------------------------------
	 #   XML::Reader->new(\$text, {filter => 4,		   parse_ct => 1, parse_pi => 1});
	 #   XML::Reader->new(\$text, {filter => 4, mode => 'pyx', parse_ct => 1, parse_pi => 1});
	 #   XML::Reader->new(\$text, {		    mode => 'pyx', parse_ct => 1, parse_pi => 1});

	 while ($rdr->iterate) {
	     printf "Path %-15s	v=%s ",	$rdr->path, $rdr->is_value;

	     if	   ($rdr->is_start)   {	print "Found start tag ", $rdr->tag, "\n"; }
	     elsif ($rdr->is_end)     {	print "Found end tag   ", $rdr->tag, "\n"; }
	     elsif ($rdr->is_decl)    {	my %h =	%{$rdr->dec_hash};
					print "Found decl     ",  join('', map{" $_='$h{$_}'"} sort keys %h), "\n"; }
	     elsif ($rdr->is_proc)    {	print "Found proc      ", "t=",	   $rdr->proc_tgt, ", d=", $rdr->proc_data, "\n"; }
	     elsif ($rdr->is_comment) {	print "Found comment   ", $rdr->comment, "\n"; }
	     elsif ($rdr->is_attr)    {	print "Found attribute ", $rdr->attr, "='", $rdr->value, "'\n";	}
	     elsif ($rdr->is_text)    {	print "Found text      ", $rdr->value, "\n"; }
	 }

       Voici le	rA(C)sultat:

	 Path /		      v=0 Found	decl	  version='1.0'
	 Path /parent	      v=0 Found	start tag parent
	 Path /parent/@abc    v=1 Found	attribute abc='def'
	 Path /parent	      v=0 Found	proc	  t=pt,	d=hmf
	 Path /parent	      v=1 Found	text	  dskjfh
	 Path /parent	      v=0 Found	comment	  remark
	 Path /parent/child   v=0 Found	start tag child
	 Path /parent/child   v=1 Found	text	  ghi
	 Path /parent/child   v=0 Found	end tag	  child
	 Path /parent	      v=0 Found	end tag	  parent

       Notez que "v=1" (c'est A	 dire $rdr->"is_value" == 1) pour tous les
       textes et pour tous les attributs.

   Option filter 5 mode	branches
       Avec option {filter => 5, mode => 'branches'}, on spA(C)cifie une (ou
       plusieurs) racines ("roots"), chaque racine a une collection de
       "branches". En rA(C)sultat on obtient un	enregistrement pour chaque
       "root" dans l'aborescence XML.

       Une racine peut commencer par un	slash simple (par ex. {root =>
       '/tag1/tag2'}), dans ce cas la racine est absolue. Ou la	racine peut
       commencer par un	double-slash (par ex. {root => '//tag1/tag2'}),	dans
       ce cas la racine	est relative. Si la racine ne commence pas par un
       slash, dans ce cas la racine est	A(C)galement relative.

       Chaque enregistrement contient les A(C)lA(C)ments qui ont A(C)tA(C)
       spA(C)cifiA(C) dans les "branches". (il y a un cas particulier: quand
       la branche est '*', dans	ce cas l'aborescence du	sous-arbre est
       construit)

       Pour obtenir des	valeurs	qui sont spA(C)cifiA(C)es dans les branches,
       on peut utiliser	la fonction $rdr->rvalue.

       Voici un	exemple:

	 use XML::Reader qw(XML::Parser);

	 my $line2 = q{
	 <data>
	   <supplier>ggg</supplier>
	   <customer name="o'rob" id="444">
	     <street>pod alley</street>
	     <city>no city</city>
	   </customer>
	   <customer1 name="troy" id="333">
	     <street>one way</street>
	     <city>any city</city>
	   </customer1>
	   <tcustomer name="nbc" id="777">
	     <street>away</street>
	     <city>acity</city>
	   </tcustomer>
	   <supplier>hhh</supplier>
	   <zzz>
	     <customer name='"sue"' id="111">
	       <street>baker street</street>
	       <city>sidney</city>
	     </customer>
	   </zzz>
	   <order>
	     <database>
	       <customer name="&lt;smith&gt;" id="652">
		 <street>high street</street>
		 <city>boston</city>
	       </customer>
	       <customer name="&amp;jones" id="184">
		 <street>maple street</street>
		 <city>new york</city>
	       </customer>
	       <customer name="stewart"	id="520">
		 <street>  ring	  road	 </street>
		 <city>	 "'&amp;&lt;&#65;&gt;'"	 </city>
	       </customer>
	     </database>
	   </order>
	   <dummy value="ttt">test</dummy>
	   <supplier>iii</supplier>
	   <supplier>jjj</supplier>
	   <p>
	     <p>b1</p>
	     <p>b2</p>
	   </p>
	   <p>
	     b3
	   </p>
	 </data>
	 };

       On veut lire les	A(C)lA(C)ments "name", "street"	et "city" de tous les
       clients dans le chemin relatif ('customer') et on veut A(C)galement
       lire les	fournisseurs dans le chemin absolu ('/data/supplier'). Puis,
       on veut lire les	clients	dans le	chemin relatif ('//customer') en
       format sous-arborescence	XML (voir {branch => '*'}). Finalement on veut
       lire le chemin relatif ('p') en format sous-arborescence	XML.

       Les donnA(C)es pour la premiA"re	racine ('customer') sont identifiable
       par $rdr->rx == 0, les donnA(C)es pour la deuxiA"me racine
       ('/data/supplier') sont identifiable par	$rdr->rx == 1, les donnA(C)es
       pour la troisiA"me racine ('//customer')	sont identifiable par $rdr->rx
       == 2, les donnA(C)es pour la quatriA"me racine ('p') sont identifiable
       par $rdr->rx == 3 et les	donnA(C)es pour	la cinquiA"me racine
       ('//customer') sont identifiable	par $rdr->rx ==	4.

       Dans l'exemple ci-dessous, le paramA"tre	{branch	=> '*'}	indique	que le
       rA(C)sultat sera	du XML et le paramA"tre	{branch	=> '+'}	indique	que le
       rA(C)sultat sera	une liste des instructions PYX.

       Dans le programme ci-dessus on va utiliser la fonction $rdr->rvalue
       pour lire les donnees:

	 my $rdr = XML::Reader->new(\$line2, {filter =>	5},
	   { root => 'customer',       branch => ['@name', 'street', 'city'] },
	   { root => '/data/supplier', branch => ['/']			     },
	   { root => '//customer',     branch => '*' },
	   { root => 'p',	       branch => '*' },
	   { root => '//customer',     branch => '+' },
	 );

	 # les trois alternatives ci-dessous sont equivalent:
	 # --------------------------------------------------
	 #   XML::Reader->new(\$line2, {filter => 5,		       });
	 #   XML::Reader->new(\$line2, {filter => 5, mode => 'branches'});
	 #   XML::Reader->new(\$line2, {	     mode => 'branches'});

	 my $root0 = '';
	 my $root1 = '';
	 my $root2 = '';
	 my $root3 = '';
	 my $root4 = '';

	 my $path0 = '';

	 while ($rdr->iterate) {
	     if	($rdr->rx == 0)	{
		 $path0	.= "  ".$rdr->path."\n";
		 for ($rdr->rvalue) {
		     $root0 .= sprintf "  Cust:	Name = %-7s Street = %-12s City	= %s\n", $_->[0], $_->[1], $_->[2];
		 }
	     }
	     elsif ($rdr->rx ==	1) {
		 for ($rdr->rvalue) {
		     $root1 .= "  Supp:	Name = $_->[0]\n";
		 }
	     }
	     elsif ($rdr->rx ==	2) {
		 for ($rdr->rvalue) {
		     $root2 .= "  Xml: $_\n";
		 }
	     }
	     elsif ($rdr->rx ==	3) {
		 for ($rdr->rvalue) {
		     $root3 .= "  P: $_\n";
		 }
	     }
	     elsif ($rdr->rx ==	4) {
		 for ($rdr->rvalue) {
		     local $" =	"', '";
		     $root4 .= "  Pyx: '@$_'\n";
		 }
	     }
	 }

	 print "root0:\n$root0\n";
	 print "path0:\n$path0\n";
	 print "root1:\n$root1\n";
	 print "root2:\n$root2\n";
	 print "root3:\n$root3\n";
	 print "root4:\n$root4\n";

       Voici le	rA(C)sultat:

	 root0:
	   Cust: Name =	o'rob	Street = pod alley    City = no	city
	   Cust: Name =	"sue"	Street = baker street City = sidney
	   Cust: Name =	<smith>	Street = high street  City = boston
	   Cust: Name =	&jones	Street = maple street City = new york
	   Cust: Name =	stewart	Street = ring road    City = "'&<A>'"

	 path0:
	   /data/customer
	   /data/zzz/customer
	   /data/order/database/customer
	   /data/order/database/customer
	   /data/order/database/customer

	 root1:
	   Supp: Name =	ggg
	   Supp: Name =	hhh
	   Supp: Name =	iii
	   Supp: Name =	jjj

	 root2:
	   Xml:	<customer id='444' name='o&apos;rob'><street>pod alley</street><city>no	city</city></customer>
	   Xml:	<customer id='111' name='"sue"'><street>baker street</street><city>sidney</city></customer>
	   Xml:	<customer id='652' name='&lt;smith&gt;'><street>high street</street><city>boston</city></customer>
	   Xml:	<customer id='184' name='&amp;jones'><street>maple street</street><city>new york</city></customer>
	   Xml:	<customer id='520' name='stewart'><street>ring road</street><city>"'&amp;&lt;A&gt;'"</city></customer>

	 root3:
	   P: <p><p>b1</p><p>b2</p></p>
	   P: <p>b3</p>

	 root4:
	   Pyx:	'(customer', 'Aid 444',	'Aname o'rob', '(street', '-pod	alley',	')street', '(city', '-no city',	')city', ')customer'
	   Pyx:	'(customer', 'Aid 111',	'Aname "sue"', '(street', '-baker street', ')street', '(city', '-sidney', ')city', ')customer'
	   Pyx:	'(customer', 'Aid 652',	'Aname <smith>', '(street', '-high street', ')street', '(city',	'-boston', ')city', ')customer'
	   Pyx:	'(customer', 'Aid 184',	'Aname &jones',	'(street', '-maple street', ')street', '(city',	'-new york', ')city', ')customer'
	   Pyx:	'(customer', 'Aid 520',	'Aname stewart', '(street', '-ring road', ')street', '(city', '-"'&<A>'"', ')city', ')customer'

       Nous pouvons A(C)galement utiliser la fonction $rdr->value pour obtenir
       les mAames donnA(C)es:

	 my $rdr = XML::Reader->new(\$line2, {filter =>	5},
	   { root => 'customer',       branch => ['@name', 'street', 'city'] },
	   { root => 'p',	       branch => '*' },
	 );

	 # les trois alternatives ci-dessous sont equivalent:
	 # --------------------------------------------------
	 #   XML::Reader->new(\$line2, {filter => 5,		       });
	 #   XML::Reader->new(\$line2, {filter => 5, mode => 'branches'});
	 #   XML::Reader->new(\$line2, {	     mode => 'branches'});

	 my $out0 = '';
	 my $out1 = '';

	 while ($rdr->iterate) {
	     if	($rdr->rx == 0)	{
		 my @rv	= $rdr->value;
		 $out0 .= sprintf "  Cust: Name	= %-7s Street =	%-12s City = %s\n", $rv[0], $rv[1], $rv[2];
	     }
	     elsif ($rdr->rx ==	1) {
		 $out1 .= "  P:	".$rdr->value."\n";
	     }
	 }

	 print "output0:\n$out0\n";
	 print "output1:\n$out1\n";

       Voici le	rA(C)sultat:

	 output0:
	   Cust: Name =	o'rob	Street = pod alley    City = no	city
	   Cust: Name =	"sue"	Street = baker street City = sidney
	   Cust: Name =	<smith>	Street = high street  City = boston
	   Cust: Name =	&jones	Street = maple street City = new york
	   Cust: Name =	stewart	Street = ring road    City = "'&<A>'"

	 output1:
	   P: <p><p>b1</p><p>b2</p></p>
	   P: <p>b3</p>

       Il faut dire ici	que le rA(C)sultat "root3" / "output1" { root => 'p',
       branch => '*' } contient	toujours le sous-arbre XML le plus important.
       Ou dit autrement: la sortie "P: <p>b1</p>" et "P: <p>b2</p>" n'est pas
       possible, car une ligne plus importante qui contient les	lignes "P:
       <p>b1</p>" et "P: <p>b2</p>" exsiste dA(C)jA : cette ligne est "P:
       <p><p>b1</p><p>b2</p></p>".

OPTION DUPATT
       L'option	dupatt permet de lire multiples	attributs avec le mAame	nom
       dans une	seule valeur. Le principe fonctionne par la concatenation des
       diffA(C)rentes valeurs dans une seule variable, sA(C)parA(C) par	un
       caractA"re spA(C)cial. La liste des attributs est ensuite triA(C) par
       order alphabA(C)tique.

       L'option	dupatt est valable uniquement si XML::Reader a A(C)tA(C)
       utilisA(C) avec l'option	XML::Parsepp.

       Par exemple, le code suivant concatA"ne les attribut doublons avec le
       caractA"re "|": (La chaA(R)ne de	caractA"res ($str) {dupatt => $str}
       est limitA(C) A	des caractA"res	Ascii visibles,	sauf les caractA"res
       alpha-numA(C)riques, ' ou ")

	 use XML::Reader qw(XML::Parser);

	 my $text = q{<data><item a2="abc" a1="def" a2="ghi"></item></data>}

	 my $rdr = XML::Reader->new(\$text, {dupatt => '|'});
	 while ($rdr->iterate) {
	     printf "Path: %-19s, Value: %s\n",	$rdr->path, $rdr->value;
	 }

       Voici le	rA(C)sultat du programme:

	 Path: /data		  , Value:
	 Path: /data/item/@a1	  , Value: def
	 Path: /data/item/@a2	  , Value: abc|ghi
	 Path: /data/item	  , Value:
	 Path: /data		  , Value:

EXEMPLES
       Examinons-nous le XML suivant, oA^1 nous	souhaitons extraire les
       valeurs dans la balise <item> (c'est la premiA"re partie	'start...', et
       non pas la partie 'end...' qui nous intA(C)resse), ensuite les
       attributs "p1" et "p3". La balise <item>	doit Aatre dans	le chemin
       '/start/param/data (et non pas dans le chemin /start/param/dataz).

	 my $text = q{
	   <start>
	     <param>
	       <data>
		 <item p1="a" p2="b" p3="c">start1 <inner p1="p">i1</inner> end1</item>
		 <item p1="d" p2="e" p3="f">start2 <inner p1="q">i2</inner> end2</item>
		 <item p1="g" p2="h" p3="i">start3 <inner p1="r">i3</inner> end3</item>
	       </data>
	       <dataz>
		 <item p1="j" p2="k" p3="l">start9 <inner p1="s">i9</inner> end9</item>
	       </dataz>
	       <data>
		 <item p1="m" p2="n" p3="o">start4 <inner p1="t">i4</inner> end4</item>
	       </data>
	     </param>
	   </start>};

       Nous expectons exactement 4 lignes de sortie dans le rA(C)sultat	(c'est
       A  dire la ligne	'dataz'	/ 'start9' ne fait pas partie du rA(C)sultat):

	 item =	'start1', p1 = 'a', p3 = 'c'
	 item =	'start2', p1 = 'd', p3 = 'f'
	 item =	'start3', p1 = 'g', p3 = 'i'
	 item =	'start4', p1 = 'm', p3 = 'o'

   Exemple filter 2 mode attr-bef-start
       Ci-dessous un programme pour parser le XML avec l'option	{filter	=> 2,
       mode => 'attr-bef-start'}. (Notez que le	prA(C)fixe
       '/start/param/data/item'	est renseignA(C) dans l'option {using =>} de
       la fonction new). En plus, nous avons besoins de	2 variables scalaires
       '$p1' et	'$p3' pour enregistrer les paramA"tres '/@p1' et '/@p3'	et les
       transfA(C)rer dans la partie '$rdr->is_start' du	programme, oA^1	on
       peut les	afficher.

	 my $rdr = XML::Reader->new(\$text,
	   {mode => 'attr-bef-start', using => '/start/param/data/item'});

	 my ($p1, $p3);

	 while ($rdr->iterate) {
	     if	   ($rdr->path eq '/@p1') { $p1	= $rdr->value; }
	     elsif ($rdr->path eq '/@p3') { $p3	= $rdr->value; }
	     elsif ($rdr->path eq '/' and $rdr->is_start) {
		 printf	"item =	'%s', p1 = '%s', p3 = '%s'\n",
		   $rdr->value,	$p1, $p3;
	     }
	     unless ($rdr->is_attr) { $p1 = undef; $p3 = undef;	}
	 }

   Exemple filter 3 mode attr-in-hash
       Avec l'option {filter =>	3, mode	=> 'attr-in-hash'}, nous pouvons
       annuler les deux	variables '$p1'	et '$p3'. Le programme devient assez
       simple:

	 my $rdr = XML::Reader->new(\$text,
	   {mode => 'attr-in-hash', using => '/start/param/data/item'});

	 while ($rdr->iterate) {
	     if	($rdr->path eq '/' and $rdr->is_start) {
		 printf	"item =	'%s', p1 = '%s', p3 = '%s'\n",
		   $rdr->value,	$rdr->att_hash->{p1}, $rdr->att_hash->{p3};
	     }
	 }

   Exemple filter 4 mode pyx
       Avec l'option {filter =>	4, mode	=> 'pyx'}, par contre, le programme
       devient plus compliquA(C): Comme	dA(C)jA	 montrA(C) dans	l'exemple
       {filter => 2, mode => 'attr-bef-start'},	nous avons besoin de deux
       variables scalaires ('$p1' et '$p3') pour enregistrer les paramA"tres
       '/@p1' et '/@p3'	et les transfA(C)rer A	l'endoit oA^1 on peut les
       afficher. En plus, nous avons besoin de compter les valeurs de texte
       (voir variable '$count' ci-dessous), afin d'identifier la premiA"re
       partie du texte 'start...' (ce que nous voulons afficher) et supprimer
       la deuxiA"me partie du texte 'end...' (ce que nous ne voulons pas
       afficher).

	 my $rdr = XML::Reader->new(\$text,
	   {mode => 'pyx', using => '/start/param/data/item'});

	 my ($count, $p1, $p3);

	 while ($rdr->iterate) {
	     if	   ($rdr->path eq '/@p1') { $p1	= $rdr->value; }
	     elsif ($rdr->path eq '/@p3') { $p3	= $rdr->value; }
	     elsif ($rdr->path eq '/') {
		 if    ($rdr->is_start)	{ $count = 0; $p1 = undef; $p3 = undef;	}
		 elsif ($rdr->is_text) {
		     $count++;
		     if	($count	== 1) {
			 printf	"item =	'%s', p1 = '%s', p3 = '%s'\n",
			   $rdr->value,	$p1, $p3;
		     }
		 }
	     }
	 }

   Exemple filter 5 mode branches
       On peut combiner	{filter	=> 5, mode => 'branches'} avec des expressions
       rA(C)guliA"res pour parser les donnA(C)es XML:

	 my $rdr = XML::Reader->new(\$text, {mode => 'branches'},
	   { root => '/start/param/data/item', branch => '*' });

	 while ($rdr->iterate) {
	     if	($rdr->value =~	m{\A <item
		 (?:\s+	p1='([^']*)')?
		 (?:\s+	p2='([^']*)')?
		 (?:\s+	p3='([^']*)')?
		 \s* > ([^<]*) <}xms) {
		 printf	"item =	'%s', p1 = '%s', p3 = '%s'\n", $4, $1, $3;
	     }
	 }

   Exemple condition d'attribut
       Ci-dessous un autre document XML	($text3):

	 my $text3 = q{
	   <data>
	     <database loc="alpha">
	       <item>
		 <customer name="smith"	id="652">
		   <street>high	street</street>
		   <city>rio</city>
		 </customer>
		 <customer name="jones"	id="184">
		   <street>maple street</street>
		   <city>new york</city>
		 </customer>
		 <customer name="gates"	id="520">
		   <street>ring	road</street>
		   <city>dallas</city>
		 </customer>
		 <customer name="smith"	id="800">
		   <street>which way</street>
		   <city>ny</city>
		 </customer>
	       </item>
	     </database>
	     <database loc="beta">
	       <item>
		 <customer name="smith"	id="001">
		   <street>nowhere</street>
		   <city>st malo</city>
		 </customer>
		 <customer name="jones"	id="002">
		   <street>all the way</street>
		   <city>leeds</city>
		 </customer>
		 <customer name="gates"	id="003">
		   <street>bypass</street>
		   <city>rome</city>
		 </customer>
	       </item>
	     </database>
	     <database loc="alpha">
	       <item>
		 <customer name="peter"	id="444">
		   <street>upton way</street>
		   <city>motown</city>
		 </customer>
		 <customer name="gates"	id="959">
		   <street>don't leave me this way</street>
		   <city>cambridge</city>
		 </customer>
	       </item>
	     </database>
	     <database loc="alpha">
	       <item>
		 <customer name="smith"	id="881">
		   <street>anyway</street>
		   <city>big apple</city>
		 </customer>
		 <customer name="thatcher" id="504">
		   <street>baker street</street>
		   <city>oxford</city>
		 </customer>
	       </item>
	     </database>
	   </data>
	 };

       En utilisant des	chemins	(root => ... and branch	=> ...)	on peut
       rajouter	des conditions d'attribut ('/path1[@attr="val"]/...'), par
       ex.:

	 my $rdr = XML::Reader->new(\$text3, {mode => 'branches', sepchar => '|'}, {
	   root	  => '/data/database[@loc="alpha"]',
	   branch => [
	     'item/customer[@name="smith"]/city',
	     'item/customer[@name="gates"]/city',
	   ]});

	 while ($rdr->iterate) {
	     my	($smith, $gates) = $rdr->value;

	     $smith = defined($smith) ?	"'$smith'" : 'undef';
	     $gates = defined($gates) ?	"'$gates'" : 'undef';

	     printf "smith = %-12s, gates = %s\n", $smith, $gates;
	 }

       Voici le	rA(C)sultat:

	 smith = 'rio|ny'    , gates = 'dallas'
	 smith = undef	     , gates = 'cambridge'
	 smith = 'big apple' , gates = undef

FONCTIONS
   Fonction slurp_xml
       La fonction slurp_xml lit un fichier XML	et aspire son contenu dans une
       rA(C)fA(C)rence A  une liste. Voici un exemple oA^1 nous	souhaitons
       aspirer le nom, la rue et la ville de tous les clients dans le chemin
       '/data/order/database/customer'.	Nous souhaitons	aussi d'aspirer	le
       'supplier' dans le chemin '/data/supplier'.

	 use XML::Reader qw(XML::Parser	slurp_xml);

	 my $line2 = q{
	 <data>
	   <supplier>ggg</supplier>
	   <supplier>hhh</supplier>
	   <order>
	     <database>
	       <customer name="smith" id="652">
		 <street>high street</street>
		 <city>boston</city>
	       </customer>
	       <customer name="jones" id="184">
		 <street>maple street</street>
		 <city>new york</city>
	       </customer>
	       <customer name="stewart"	id="520">
		 <street>ring road</street>
		 <city>dallas</city>
	       </customer>
	     </database>
	   </order>
	   <dummy value="ttt">test</dummy>
	   <supplier>iii</supplier>
	   <supplier>jjj</supplier>
	 </data>
	 };

	 my $aref = slurp_xml(\$line2,
	   { root => '/data/order/database/customer', branch =>	['@name', 'street', 'city'] },
	   { root => '/data/supplier',		      branch =>	'*'			    },
	 );

	 for (@{$aref->[0]}) {
	     printf "Cust: Name	= %-7s Street =	%-12s City = %s\n", $_->[0], $_->[1], $_->[2];
	 }

	 print "\n";

	 for (@{$aref->[1]}) {
	     printf "S:	%s\n", $_;
	 }

       Le premier paramA"tre de	slurp_xml est ou le nom	du fichier (ou une une
       rA(C)fA(C)rence A  un scalaire, ou une rA(C)fA(C)rence A	 un fichier
       ouvert) du XML qu'on veut aspirer.  Dans	notre cas nous avons une
       rA(C)fA(C)rence A  un scalaire \$line2. Le paramA"tre suivant est la
       racine de l'arbre qu'on veut aspirer (dans notre	cas c'est
       '/data/order/database/customer')	et nous	donnons	une liste des
       A(C)lA(C)ments que nous souhaitons sA(C)lectionner, relative A  la
       racine. Dans notre cas c'est ['@name', 'street',	'city']. Le paramA"tre
       suivant est la deuxiA"me	racine (dA(C)finition root/branch), dans ce
       cas c'est root => '/data/supplier' avec branch => ['/'].

       Voici le	rA(C)sultat:

	 Cust: Name = smith   Street = high street  City = boston
	 Cust: Name = jones   Street = maple street City = new york
	 Cust: Name = stewart Street = ring road    City = dallas

	 S: <supplier>ggg</supplier>
	 S: <supplier>hhh</supplier>
	 S: <supplier>iii</supplier>
	 S: <supplier>jjj</supplier>

       Le fonctionnement de slurp_xml est similaire A  XML::Simple, c'est A
       dire il lit toutes les donnA(C)es dans un seul coup dans	une structure
       en mA(C)moire. En revanche, la diffA(C)rence est	que slurp_xml permet
       de spA(C)cifier les donnA(C)es qu'on veut avant de faire	l'aspiration,
       ce qui rA(C)sulte dans une structure en mA(C)moire souvent plus petite
       et moins	compliquA(C)e.

       On peut utiliser	slurp_xml() avec des attributs doublons. Dans ce cas
       il faut faire deux choses: PremiA"rement	il faut	faire un "use
       XML::Reader" avec "qw(XML::Parsepp slurp_xml)". DeuxiA"mement il	faut
       faire appel A  slurp_xml	avec l'option {	dupatt => '|' }, comme dans
       l'exemple ci-dessous:

	 use XML::Reader qw(XML::Parser	slurp_xml);

	 my $line3 = q{<data atr1='abc'	atr2='def' atr1='ghi'></data>};

	 my $aref = slurp_xml(\$line3,
	   { dupatt => '|' },
	   { root => '/', branch => '*'	});

	 print $aref->[0][0], "\n";

       Voici le	rA(C)sultat:

	 <data atr1='abc|ghi' atr2='def'></data>

AUTEUR
       Klaus Eichner, Mars 2009

COPYRIGHT ET LICENSE
       Voici le	texte original en Anglais:

       Copyright (C) 2009 by Klaus Eichner.

       All rights reserved. This program is free software; you can
       redistribute it and/or modify it	under the terms	of the artistic
       license 2.0, see
       http://www.opensource.org/licenses/artistic-license-2.0.php

MODULES	ASSOCIES
       Si vous souhaitez A(C)crire du XML, je propose d'utiliser le module
       "XML::Writer" ou	"XML::MinWriter". Chacun de ces	deux modules se
       prA(C)sente avec	une interface simple pour A(C)crire un fichier XML. Si
       vous ne mA(C)langez pas le texte	et les balises (ce qu'on appelle en
       Anglais "non-mixed content XML"), je propose de mettre les options
       DATA_MODE=>1 et DATA_INDENT=>2, ainsi votre rA(C)sultat sera proprement
       formatA(C) selon	les rA"gles XML.

REFERENCES
       XML::TokeParser,	XML::Simple, XML::Parser, XML::Parsepp,
       XML::Reader::RS,	XML::Reader::PP, XML::Parser::Expat, XML::TiePYX,
       XML::Writer, XML::MinWriter.

perl v5.32.0			  2018-11-21		     XML::Reader_fr(3)

NAME | TRADUCTION | SYNOPSIS | UTILISATION | DESCRIPTION | INTERFACE | OPTION USING | OPTION PARSE_CT | OPTION PARSE_PI | OPTION FILTER / MODE | OPTION DUPATT | EXEMPLES | FONCTIONS | AUTEUR | COPYRIGHT ET LICENSE | MODULES ASSOCIES | REFERENCES

Want to link to this manual page? Use this URL:
<https://www.freebsd.org/cgi/man.cgi?query=XML::Reader_fr&sektion=3&manpath=FreeBSD+12.1-RELEASE+and+Ports>

home | help