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

FreeBSD Manual Pages

  
 
  

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

NAME
       XML::Reader_de -	Lesen von XML-Dateien und Bereitstellung der Pfad
       information basierend auf einem Pull-Parser.

~
       This document is	the German 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

       Dieses Dokument ist die Deutsche	Abersetzung aus	dem Englischen des
       Moduls XML::Reader. Um den Perl Quelltext des Moduls zu lesen, gehen
       Sie bitte zur Datei 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;
	 }

       Dieses Programm erzeugt folgendes Resultat:

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

       Man kann	den Aufruf von XML::Reader->new(...) mit einem eval {...}
       verpacken um zu testen ob der Aufruf erfolgreich	war:

	 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 ...
	 }

BENUTZUNG
       Normalerweise benutzt man XML::Reader nicht direkt, sondern man benutzt
       entweder	XML::Reader::RS	(welches XML::Parser benutzt) oder man benutzt
       XML::Reader::PP (welches	XML::Parsepp benutzt).

       Falls man dennoch XML::Reader direkt benutzen will, hier	ist die
       Beschreibung wie	man zwischen XML::Parser und XML::Parsepp auswAxhlt:

       Wenn bei	der "use"-Anweisung keine Angabe zum Parser Modul gemacht
       wird, lAxdt XML::Reader zunAxchst XML::Parser.  Das funktioniert	sehr
       gut, ausser in den FAxllen in denen kein	C-compiler zur verfA1/4gung
       steht um	XML::Parser zu installieren.  Wenn also	das Laden von
       XML::Parser fehlschlAxgt, wird XML::Parsepp als Ersatz geladen.

       Es ist auch mA<paragraph>glich, den Parser explizit auszuwAxhlen.  Im
       folgenden Beispiel wird XML::Parser ausgewAxhlt,	so dass	nun die
       Abersetzung des Moduls fehlschlAxgt, wenn XML::Parser nicht
       verfA1/4gbar ist.

	 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;
	 }

       Das einzige was man beachten muss ist dass XML::Reader auf beiden
       Modulen,	XML::Parser und	XML::Parsepp, basiert.	Das bedeutet konkret
       dass wenn man XML::Reader ohne XML::Parser installieren will, dann darf
       man einfach nicht die Tests laufen lassen.

BESCHREIBUNG
       XML::Reader stellt ein einfach zu bedienendes Interface zur
       VerfA1/4gung mit	dem man	XML-Dateien sequentiell	lesen kann
       (sogenanntes "pull-mode"	parsing). Der aktuelle XML-Pfad	wird ebenfalls
       gepflegt.

       XML::Reader wurde als eine HA1/4lle A1/4ber dem bestehenden Modul
       XML::Parser/XML::Parsepp	entwickelt (ausserdem wurden einige
       Grundfunktionen des Moduls XML::TokeParser mit A1/4bernommen). Die
       bestehenden Module XML::Parser, XML::Parsepp und	XML::TokeParser
       ermA<paragraph>glichen beide das	sequentielle Verarbeiten von XML-
       Dateien,	jedoch wird in diesen Modulen der XML-Pfad nicht gepflegt.
       Ausserdem muss man mit den Modulen XML::Parser, XML::Parsepp und
       XML::TokeParser die Unterscheidung zwischen Start-Tags, End-Tags	und
       Text machen, was	meiner Meinung nach die	Sache verkompliziert (obwohl
       man auch	dieselbe Situation in XML::Reader simulieren kann, und zwar
       durch die Option	{filter	=> 4, mode => 'pyx'}, wenn es das ist was man
       will).

       Es existiert auch ein Modul namens XML::TiePYX, welches ebenfalls das
       sequentielle Verarbeiten	von XML-Dateien	erlaubt	(siehe
       <http://www.xml.com/pub/a/2000/03/15/feature/index.html>	fA1/4r eine
       EinfA1/4hrung in	PYX). Aber dennoch, auch mit XML::TiePYX ist man
       gezwungen eine Unterscheidung zwischen Start-Tags, End-Tags und Text zu
       machen und der XML-Pfad wird auch nicht gepflegt.

       Im Gegensatz dazu A1/4bersetzt XML::Reader die in der XML-Datei
       bestehenden Start-Tags, End-Tags	und Text in XPath-Axhnliche
       AusdrA1/4cke, man erhAxlt also nur einen	Pfad und einen Wert, so
       einfach ist es. (Sollte man jedoch mit XML::Reader PYX-kompatible
       AusdrA1/4cke erzeugen wollen, dann kann man das auch mit	der Option
       {filter => 4, mode => 'pyx'}, wie zuvor erwAxhnt, erreichen).

       Aber kommen wir zurA1/4ck zur normalen Benutzung	von XML::Reader,
       dieses hier ist eine Beispiel XML-Datei,	kodiert	in der Variablen
       '$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>
	 };

       Diese Beispiel XML-Datei	kann man mit XML::Reader lesen,	und zwar indem
       man die Methode "iterate" verwendet um das jeweils nAxchste XML-Element
       zu lesen. Danach	kann man dann mit den Methoden "path" und "value" den
       Pfad und	den aktuellen Wert lesen.

       Man kann	ausserdem, wenn	man es denn so mA<paragraph>chte, die
       jeweiligen Start- und End-Tags erkennen:	Es existiert die Methode
       "is_start", die genau dann 1 zurA1/4ckgibt, wenn	an der aktuellen
       Positon in der XML-Datei	ein Start-Tag existiert, ansonsten gibt	die
       Methode 0 zurA1/4ck. Es existiert ebenso	die zugehA<paragraph>rige
       Methode "is_end", die genau dann	1 zurA1/4ckgibt, wenn nach der
       aktuellen Positon in der	XML-Datei ein End-Tag existiert, ansonsten
       gibt die	Methode	0 zurA1/4ck.

       Es existieren zusAxtzlich die Methoden "tag", "attr", "type" und
       "level".	Die Methode "tag" liefert den aktuellen	Tag-Namen, "attr"
       liefert den Attribut-Namen, "type" liefert entweder 'T' fA1/4r Text
       oder '@'	fA1/4r Attribute, "level" liefert die im Moment	aktive
       Verschachtelungstiefe (das ist ein numerischer Wert >= 0)

       Hier folgend wird, um das Prinzip zu erklAxren, ein Beispielprogramm
       aufgefA1/4hrt, welches die vorangegangene XML-Datei in '$line1'
       einliest...

	 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;
	 }

       ...und das hier ist das Resultat:

	  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
   Objekt Erstellung
       Um ein Objekt vom Typ XML::Reader zu erstellen, wird folgende Syntax
       verwendet:

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

       Der Parameter $data (welcher immer mit angegeben	werden muss) ist
       entweder	der Name einer XML-Datei, oder eine URL	die mit	'http://...'
       beginnt,	oder eine Referenz auf eine Zeichenkette (sodass der Inhalt
       dieser Zeichenkette als XML verarbeitet werden kann), oder ein zuvor
       geA<paragraph>ffnetes Dateihandle, z.B. \*STDIN,	(in diesem Fall	wird
       einfach das Filehandle benutzt um die XML-Daten zu lesen).

       Hier ist	ein Beispiel um	ein Objekt des Typs XML::Reader	mit einem
       einfachen Datei-Namen zu	erzeugen:

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

       Hier ist	ein weiteres Beispiel um ein Objekt des	Typs XML::Reader mit
       einer Referenz auf eine Zeichenkette zu erzeugen:

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

       Hier ist	noch ein weiteres Beispiel um ein Objekt des Typs XML::Reader
       mit einem zuvor geA<paragraph>ffneneten Dateihandle zu erzeugen:

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

       Hier ist	schliesslich ein Beispiel um ein Objekt	des Typs XML::Reader
       mit \*STDIN zu erzeugen:

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

       Eine oder mehrere Optionen kA<paragraph>nnen als	eine Hash-Referenz
       hinzugefA1/4gt werden:

       Option {parse_ct	=> }
	   Option {parse_ct => 1} ermA<paragraph>glicht	es XML-Kommentare zu
	   lesen, die Voreinstellung ist {parse_ct => 0}

       Option {parse_pi	=> }
	   Option {parse_pi => 1} ermA<paragraph>glicht	es processing-
	   instructions	und XML-Declarations zu	lesen, die Voreinstellung ist
	   {parse_pi =>	0}

       Option {using =>	}
	   Option {using => } ermA<paragraph>glicht es einen Teil-Baum der
	   XML-Datei zu	selektieren.

	   Die Syntax hierfA1/4r lautet: {using	=> ['/pfad1/pfad2/pfad3',
	   '/pfad4/pfad5/pfad6']}

       Option {filter => } und {mode =>	}
	   Option {filter => 2}	oder {mode => 'attr-bef-start'}	zeigt alle
	   XML-Zeilen an, einschliesslich der Attribute.

	   Option {filter => 3}	oder {mode => 'attr-in-hash'} entfernt die
	   Attribut-Zeilen (d.h. alle Zeilen mit $rdr->type eq '@' werden
	   entfernt). Anstelle dessen werden die Attribute in einer Hash-
	   Referenz $rdr->att_hash zurA1/4ckgeliefert.

	   Option {filter => 4}	oder {mode => 'pyx'} bricht alle Zeilen	in
	   individuelle	Start-Tags, End-Tags, Attribute, Kommentare und
	   Processing-Instructions auf.	Damit wird die Verarbeitung der	XML-
	   Datei im PYX-Format ermA<paragraph>glicht.

	   Option {filter => 5}	oder {mode => 'branches'} selektiert nur die
	   Daten fA1/4r	die vorgegebenen Wurzeln ("root"). Die Datenelemente
	   jeder Wurzel	werden in einer	Array Referenz (wie spezifiziert durch
	   den "branch"	Parameter) gesammelt und dann zurA1/4ckgegeben wenn
	   der "branch"	komplett ist. Diese Vorgehensweise liegt auf halbem
	   Weg zwischen	der Option "using" (wo alle Elemente einzeln
	   zurA1/4ckgeliefert werden) und der Funktion "slurp_xml" (wo alle
	   Elemente in einem "branch" gesammelt	werden,	und alle "branches"
	   dann	am Ende	in einer grossen Speicherstruktur auf einmal
	   zurA1/4ckgeliefert werden).

	   Die Syntax lautet {filter =>	2|3|4|5, mode =>
	   'attr-bef-start'|'attr-in-hash'|'pyx'|'branches'}, die
	   Voreinstellung ist {filter => 2, mode => 'attr-bef-start'}

       Option {strip =>	}
	   Option {strip => 1} entfernt	sowohl fA1/4hrende, als	auch am	Ende
	   befindliche Leerzeichen in Text und in Kommentaren. (Attributen
	   bleiben hiervon unberA1/4hrt). {strip => 0} lAxsst Text und
	   Kommentare so wie sie in der	XML-Datei existieren, mit alle
	   Leerzeichen.

	   Die Syntax hierfA1/4r lautet	{strip => 0|1},	die Voreinstellung ist
	   {strip => 1}

       Option {dupatt => }
	   Die Option {dupatt => '*'} ermA<paragraph>glicht Attribute, die
	   mehrfach Auftreten, zu verarbeiten. Die verschiedenen Werte werden
	   dann	mit dem	'*'-Zeichen zu einem einzelnen Wert verbunden.

   Methoden
       Ein erfolgreich erstelltes Objekt vom Typ XML::Reader stellt folgende
       Methoden	zur VerfA1/4gung:

       iterate
	   Liest das nAxchste XML-Element. Die Methode liefert den Wert	1
	   zurA1/4ck wenn das Lesen erfolgreich	war, oder undef	falls das Ende
	   der XML-Datei erreicht wurde.

       path
	   Liefert den gesamten	Pfad des aktuellen XML-Elements	zurA1/4ck,
	   Attribute werden mit	einem fA1/4hrenden '@'-Zeichen markiert.

       value
	   Liefert den aktuellen Wert zurA1/4ck	(d.h. den Wert des aktuellen
	   Textes oder den des aktuellen Attributes).

	   Bitte beachten Sie dass wenn	{filter	=> 2 oder 3} selektiert	wurde
	   und wenn zusAxtzlich	das aktuelle Element eine XML-Deklaration ist
	   (d.h. $rdr->is_decl == 1), dann ist es ratsam den aktuellen Wert
	   nicht zu berA1/4cksichtigen (er ist dann sowieso leer). Ein
	   typisches Beispiel wAxre:

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

	   Dieses oben angegebe	Beispiel trifft	jedoch nicht zu	wenn {filter
	   => 4} aktiv ist. In diesem falle genA1/4gt ein einfaches "print
	   $rdr->value;":

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

       comment
	   Liefert den aktuellen Kommentar zurA1/4ck. Bevor man	diesen Wert
	   benutzt, sollte man mit $rdr->"is_comment" prA1/4fen	ob das
	   aktuelle Element wirklich ein Kommentar ist.

       type
	   Liefert den Typ des Wertes zurA1/4ck: 'T' fA1/4r Text, '@' fA1/4r
	   Attribute.

	   Falls Option	{filter	=> 4} aktiviert	ist, dann kann der Typ
	   folgende Werte annehmen: 'T'	fA1/4r Text, '@' fA1/4r	Attribute, 'S'
	   fA1/4r Start-Tags, 'E' fA1/4r End-Tags, '#' fA1/4r Kommentare, 'D'
	   fA1/4r XML-Declarationen, '?' fA1/4r	Processing-Instructions.

       tag Liefert den aktuellen Tag-Namen zurA1/4ck.

       attr
	   Liefert den aktuellen Attribut-Namen	zurA1/4ck (liefert eine	leere
	   Zeichenkette	zurA1/4ck falls	das aktuelle Element kein Attribut
	   ist).

       level
	   Zeigt die aktuelle Verschachtelungstiefe des	XPath-Ausdruckes an
	   (das	ist ein	numerischer Wert > 0)

       prefix
	   Liefert den PrAxfix zurA1/4ck der durch die Option {using =>	...}
	   entfernt wurde. Falls die Option {using => ...} nicht benutzt
	   wurde, wird eine leere Zeichenkette zurA1/4ckgegeben

       att_hash
	   Liefert eine	Referenz zu einem Hash zurA1/4ck der die aktuellen
	   Attribute eines Start-Tags enthAxlt (der Hash ist leer falls	der
	   aktuelle Tag	kein Start-Tag ist)

       dec_hash
	   Liefert eine	Referenz zu einem Hash zurA1/4ck der die aktuellen
	   Attribute einer XML-Declaration enthAxlt (der Hash ist leer falls
	   der aktuelle	Tag keine XML-Declaration ist)

       proc_tgt
	   Liefert den Ziel Wert (d.h. den ersten Teil)	einer Processing-
	   Instruction zurA1/4ck (eine leere Zeichenkette wird
	   zurA1/4ckgegeben falls der aktuelle Tag keine Processing-
	   Instruction ist)

       proc_data
	   Liefert den Daten Wert (d.h.	den zweiten Teil) einer	Processing-
	   Instruction zurA1/4ck (eine leere Zeichenkette wird
	   zurA1/4ckgegeben falls der aktuelle Tag keine Processing-
	   Instruction ist)

       pyx Liefert eine	Zeichenkette im	PYX-Format des aktuellen Tags
	   zurA1/4ck.

	   Das PYX-Format ist eine Zeichenkette	deren erstes Zeichen eine
	   spezielle Bedeutung hat. Dieses erste Zeichen einer jeweiligen PYX-
	   Zeichenkette	gibt den Typ des Ereignisses an	mit dem	man es zu tun
	   hat:	falls das erste	Zeichen	ein '('	ist, dann hat man es mit einem
	   Start-Tag zu	tun, wenn es ein ')' ist, dann hat man es mit einem
	   End-Tag zu tun, wenn	es ein 'A' ist,	dann hat man es	mit einem
	   Attribut zu tun, wenn es ein	'-' ist, dann hat man es mit einem
	   Text	zu tun,	wenn es	ein '?'	ist, dann hat man es mit einer
	   Processing-Instruction zu tun. (siehe
	   <http://www.xml.com/pub/a/2000/03/15/feature/index.html> fA1/4r
	   eine	EinfA1/4hrung in PYX)

	   Die Methode "pyx" macht nur Sinn falls die Option {filter =>	4}
	   aktiviert wurde, ansonsten wird undef zurA1/4ckgeliefert.

       is_start
	   Liefert 1 zurA1/4ck falls die aktuelle Position ein Start-Tag ist,
	   ansonsten wird 0 zurA1/4ckgeliefert.

       is_end
	   Liefert 1 zurA1/4ck falls die aktuelle Position ein End-Tag ist,
	   ansonsten wird 0 zurA1/4ckgeliefert.

       is_decl
	   Liefert 1 zurA1/4ck falls die aktuelle Position eine	XML-
	   Declaration ist, ansonsten wird 0 zurA1/4ckgeliefert.

       is_proc
	   Liefert 1 zurA1/4ck falls die aktuelle Position eine	Processing-
	   Instruction ist, ansonsten wird 0 zurA1/4ckgeliefert.

       is_comment
	   Liefert 1 zurA1/4ck falls die aktuelle Position ein Kommentar ist,
	   ansonsten wird 0 zurA1/4ckgeliefert.

       is_text
	   Liefert 1 zurA1/4ck falls die aktuelle Position ein Text ist,
	   ansonsten wird 0 zurA1/4ckgeliefert.

       is_attr
	   Liefert 1 zurA1/4ck falls die aktuelle Position ein Attribut	ist,
	   ansonsten wird 0 zurA1/4ckgeliefert.

       is_value
	   Liefert 1 zurA1/4ck falls die aktuelle Position ein Text oder ein
	   Attribut ist, ansonsten wird	0 zurA1/4ckgeliefert.  Diese Methode
	   ist insbesondere nA1/4tzlich	wenn {filter =>	4, mode	=> 'pyx'}
	   aktiv ist, in diesem	Falle kann man damit testen ob es sinnvoll ist
	   die Methode value() aufzurufen.

       rx  Das ist der Index des aktuellen Branches (macht nur Sinn wenn
	   {filter => 5, mode => 'branches'} gesetzt wurde).

       rvalue
	   Das ist eine	Referenz (auf einen Scalar-Wert	oder auf ein Array)
	   fA1/4r den aktuellen	Branch.	 (macht	nur Sinn wenn {filter => 5,
	   mode	=> 'branches'} gesetzt wurde). rvalue is schneller als,	aber
	   nicht so einfach zu benutzen	wie, die Axhnliche funktion value (mit
	   rvalue muss man die De-Referenzierung selber	ausfA1/4hren.

       rstem
	   Diese Funktion ist identisch	mit der	bestehenden Funktion "path"

OPTION USING
       Mit der Option {using =>	...} kann man einen Teil-Baum der XML-Datei
       selektieren.

       So funktioniert das im Detail...

       Die Option {using => ['/pfad1/pfad2/pfad3', '/pfad4/pfad5/pfad6']}
       eliminiert alle Zeilen deren Pfad nicht mit '/pfad1/pfad2/pfad3'	(oder
       nicht mit '/pfad4/pfad5/pfad6') beginnen. Das lAxsst dann nur noch
       Zeilen A1/4brig,	die dann mit '/pfad1/pfad2/pfad3' oder mit
       '/pfad4/pfad5/pfad6' beginnen.

       Diese Zeilen (die nicht eliminiert wurden) haben	dann einen kA1/4rzeren
       Pfad, weil der PrAxfix '/pfad1/pfad2/pfad3' (oder '/pfad4/pfad5/pfad6')
       entfernt	wurde. Der entfernte PrAxfix erscheint dann aber in der
       Methode prefix().

       Man kann	sagen dass die Pfade '/pfad1/pfad2/pfad3' und
       '/pfad4/pfad5/pfad6' "absolut" und "komplett" sind. Der Begriff
       "absolut" bedeutet dass die Pfade mit einem '/' beginnen	mA1/4ssen, der
       Begriff "komplett" bedeutet dass	der Pfad intern	mit einem anghAxngten
       '/'-Zeichen abgeschlossen wird.

   Beispiel mit	using
       Das folgende Programm liest eine	XML-Datei und parst sie	mit
       XML::Reader, die	Option 'using' selektiert dabei	nur einen Teil des
       XML-Baumes:

	 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;
	 }

       Das ist das Ergebnis dieses Programms:

	  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

   Beispiel ohne using
       Das folgende Programm liest eine	XML-Datei und parst sie	mit
       XML::Reader, jedoch ohne	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;
	 }

       Wie man in dem folgenden	Resultat sehen kann, werden mehr Ausgabezeilen
       geschrieben, der	PrAxfix	ist leer und der Pfad ist jetzt	lAxnger	als
       zuvor.

	  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
       Die Option {parse_ct => 1} erlaubt das Lesen von	Kommentaren
       (normalerweise werden Kommentare	von XML::Reader	ignoriert, d.h.
       {parse_ct => 0} ist die Voreinstellung).

       Hier ist	ein Beispiel wo	Kommentare, wie	voreingestellt,	ignoriert
       werden:

	 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;
	 }

       Hier ist	das Ergebnis:

	 Text 'xyz stu test'

       Jetzt ein Beispiel mit den selben XML-Daten und dem selben Algorithmus,
       ausser dass die Option {parse_ct	=> 1} jetzt aktiviert ist:

	 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;
	 }

       Hier ist	das Ergebnis:

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

OPTION PARSE_PI
       Die Option {parse_pi => 1} erlaubt das Lesen von	Processing-
       Instructions und	XML-Declarations (normalerweise	werden Processing-
       Instructions und	XML-Declarations von XML::Reader ignoriert, d.h.
       {parse_pi => 0}	ist die	Voreinstellung).

       Als Beispiel benutzen wir hier die selben XML-Daten und den selben
       Algorithmus wie zuvor, ausser dass die Option {parse_pi => 1} aktiviert
       ist (zusammen mit der schon aktivierten 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;
	 }

       Beachten	sie im obigen Programm die Zeile "unless $rdr->is_decl". Diese
       Zeile existiert damit verhindert	wird dass der Wert einer XML-
       Declaration ausgegeben wird (dieser Wert	wAxre dann sowieso leer).

       Hier ist	das Resultat:

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

OPTION FILTER /	MODE
       Die Option {filter => } oder {mode => } erlaubt verschiedene
       Grundeinstellungen zum Verarbeiten von XML-Daten.

   Option filter 2 mode	attr-bef-start
       Mit der Option {filter => 2} oder {mode => 'attr-bef-start'},
       XML::Reader erzeugt eine	Zeile fA1/4r jedes Text-Event. Falls der
       vorangehende Tag	ein Start-Tag ist, dann	wird die Methode "is_start"
       auf 1 gesetzt. Falls der	folgende Tag ein End-Tag ist, dann wird	die
       Methode "is_end"	auf 1 gesetzt. Falls der vorangehende Tag ein
       Kommentar ist, dann wird	die Methode "is_comment" auf 1 gesetzt.	Falls
       der vorangehende	Tag eine XML-Declaration ist, dann wird	die Methode
       "is_decl" auf 1 gesetzt.	Falls der vorangehende Tag eine	Processing-
       Instruction ist,	dann wird die Methode "is_proc"	auf 1 gesetzt.

       ZusAxtzlich, Attribute werden als spezielle Zeilen mit der '/@...'
       Syntax hinzugefA1/4gt.

       Option {filter => 2, mode => 'attr-bef-start'} ist die Voreinstellung.

       Hier ist	ein Beispiel...

	 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);

	 # Die folgenden vier Alternativen sind	gleichwertig:
	 # --------------------------------------------------
	 #   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;
	 }

       Dieses Programm (mit der	impliziten Option {filter => 2,	mode =>
       'attr-bef-start'} als Voreinstellung) produziert	folgendes Resultat:

	 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

       Dieselbe	Option {filter => 2, mode => 'attr-bef-start'} erlaubt die
       Erkennung der XML-Struktur mithilfe der Methoden	"is_start" und
       "is_end". Bitte beachten	Sie ebenso in dem obigen Resultat dass die
       erste Zeile ("Path: /root, Value:") zwar	leer ist, jedoch sehr wichtig
       fA1/4r die XML-Struktur ist. Daher dA1/4rfen wir	diese Zeile nicht
       vergessen.

       Betrachten wir jetzt das	selbe Beispiel (mit der	Option {filter => 2,
       mode => 'attr-bef-start'}), jedoch mit einem zusAxtzlichen Algorithmus
       um die originale	XML-Struktur wieder herzustellen. Ausserdem verlangen
       wir das normale Zeichenketten (also keine Tags und auch keine
       Attribute) mit den Zeichen "** **" markiert werden.

	 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);

	 # Die folgenden vier Alternativen sind	gleichwertig:
	 # --------------------------------------------------
	 #   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";
	     }
	 }

       ...hier ist das Resultat:

	 <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>

       ...Dieses Resultat beweist dass die originale XML-Struktur nicht
       verloren	gegangen ist.

   Option filter 3 mode	attr-in-hash
       Die Option {filter => 3,	mode =>	'attr-in-hash'}	funktioniert Axhnlich
       wie {filter => 2, mode => 'attr-bef-start'}.

       Der Unterschied jedoch ist dass mit Option {filter => 3,	mode =>
       'attr-in-hash'} alle Attribut-Zeilen eliminiert werden und anstelle
       dessen die Attribute fA1/4r ein Start-Tag im hash $rdr->att_hash()
       erscheinen.

       Damit wird die Benutzung	einer globalen %at-Variable im oben
       angegebenen Algorithmus nicht mehr notwendig und	kann daher durch die
       Konstruktion %{$rdr->att_hash} erstzt werden.

       Hier ist	ein neuer Algorithmus fA1/4r {filter =>	3}, wir	brauchen uns
       nicht mehr explizit um Attribut-Zeilen zu kA1/4mmern (d.h. wir brauchen
       nicht mehr abzufragen ob	$rdr->"type" eq	'@') und, wie schon bemerkt,
       die %at-Variable	wird ersetzt durch %{$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});

	 # Die folgenden drei Alternativen sind	gleichwertig:
	 # --------------------------------------------------
	 #   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";
	     }
	 }

       ...das Resultat fA1/4r {filter => 3, mode => 'attr-in-hash'} ist
       identisch mit dem Resultat fA1/4r {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>

       Schliesslich kA<paragraph>nnen wir (und sollten wir auch) das schreiben
       von XML einem anderen Modul A1/4berlassen.  Ich schlage hiermit vor,
       dass wir	das Modul XML::MinWriter benutzen. Hier	ist ein	Programm
       welches XML::MinWriter fA1/4r die Ausgabe von XML benutzt:

	 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();

       Hier ist	das Resultat von 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
	 >

       Das Ausgabeformat von XML::MinWriter ist	anfAxnglich
       gewA<paragraph>hnungsbedA1/4rftig, es ist jedoch	korrektes XML Format.

   Option filter 4 mode	pyx
       Obwohl es nicht die Hauptfunktion von XML::Reader darstellt, erlaubt
       die Option {filter => 4,	mode =>	'pyx'} die Erzeugung von individuellen
       Zeilen fA1/4r jeweils das Start-Tag, das	End-Tag, Kommentare,
       Processing-Instructions und XML-Declarations. Der Sinn ist eine PYX-
       kompatible Ausgabe-Zeichenkette zur weiteren Verarbeitung zu erzeugen.

       Hier ist	ein Beispiel:

	 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});

	 # Die folgenden drei Alternativen sind	gleichwertig:
	 # --------------------------------------------------
	 #   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;
	 }

       und hier	ist das	Resultat:

	 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

       Bitte berA1/4cksichtigen	Sie dass, falls	{parse_ct => 1}	gesetzt	ist,
       Kommentare in der Methode "pyx" in einem	nicht-standardisierten Format
       erzeugt werden. Die Kommentare werden dann mit einem fA1/4hrenden
       Doppelkreuz erzugt welches nicht	in der PYX-Spezifikation existiert.
       Das folgende Beispiel demonstriert diesen Fall:

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

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

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

	 # Die folgenden drei Alternativen sind	gleichwertig:
	 # --------------------------------------------------
	 #   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;
	 }

       Hier ist	das Ergebnis:

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

       Ausserdem, falls	{filter	=> 4, mode => 'pyx'} gesetzt ist, bleiben
       folgende	Methoden gA1/4ltig: ("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" und
       "att_hash"). Hier ist ein Beispiel:

	 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});

	 # Die folgenden drei Alternativen sind	gleichwertig:
	 # --------------------------------------------------
	 #   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"; }
	 }

       Hier ist	das Ergebnis:

	 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

       Bitte beachten Sie dass fA1/4r alle Texte und fA1/4r alle Attribute v=1
       gesetzt ist (d.h. $rdr->"is_value" == 1).

   Option filter 5 mode	branches
       Mit der Option {filter => 5, mode => 'branches'}	spezifiziert man eine
       (oder mehrere) Wurzeln ("root"),	jede "root" hat	eine Liste von Asten
       ("branch"). Man erhAxlt daraufhin genau einen Record fA1/4r jedes
       Auftreten der "root" in der XML Struktur. Eine Wurzel kann mit einem
       einfachen SchrAxgstrich (z.B. {root => '/tag1/tag2'}) beginnen, in
       welchem Falle der Pfad absolut zu betrachten ist, oder sie kann mit
       einem Doppel-SchrAxgstrich (z.B.	 {root => '//tag1/tag2'}) beginnen, in
       welchem Falle der Pfad relativ zu betrachten ist. Die Wurzel ist	ebenso
       relativ wenn die	Wurzel ohne SchrAxgstrich beginnt (z.B.	{root =>
       'tag1/tag2'}).

       Jeder Record enthAxlt genau die Elemente	die in der "branch" Struktur
       definiert wurden. (Als Sonderfall betrachtet man	den Ast	{branch	=>
       '*'}, in	welchem	Falle die komplette XML-Strujtur des Unterbaumes
       zurA1/4ck gegeben wird.

       Um die Element zu erhalten die in der "branch" Struktur definiert
       wurden, kann man	die Funktion $rdr->rvalue benutzen.

       Am einfachsten lAxsst sich dieses an einem Beispiel erklAxren:

	 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>
	 };

       Wir wollen aus der oben angegebenen XML-Datei die Elemente "name",
       "street"	und "city" fA1/4r den relativen	Pfad 'customer'	auslesen.
       Ausserdem wollen	wir den	Supplier im absoluten Pfad '/data/supplier'
       lesen. Dann wollen wir fA1/4r den relativen Pfad	'//customer' den XML-
       Unterbaum erhalten und schliesslich wollen wir den XML-Unterbaum	fA1/4r
       den relativen Pfad 'p' erhalten.

       Die Daten der ersten Wurzel 'customer' erkennt man anhand der Bedingung
       $rdr->rx	== 0, die Daten	der zweiten Wurzel '/data/supplier' erkennt
       man anhand der Bedingung	$rdr->rx == 1, die Daten der dritten Wurzel
       '//customer' erkennt man	anhand der Bedingung $rdr->rx == 2, die	Daten
       der vierten Wurzel 'p' erkennt man anhand der Bedingung $rdr->rx	== 3
       und die Daten der fA1/4nften Wurzel '//customer'	erkennt	man anhand der
       Bedingung $rdr->rx == 4.

       Bitte beachten Sie in dem folgenden Beispielprogramm dass der Parameter
       {branch => '*'} zur Folge hat dass eine XML Zeichenkette
       zurA1/4ckgegeben	wird und dass der Parameter {branch => '+'} zur	Folge
       hat dass	eine Liste von PYX Instruktionen zurA1/4ckgegeben wird.

       Im folgenden Programm benutzen wir die Funktion $rdr->rvalue um die
       Daten zu	erhalten:

	 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 => '+' },
	 );

	 # Die folgenden drei Alternativen sind	gleichwertig:
	 # --------------------------------------------------
	 #   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";

       Hier ist	das Ergebnis:

	 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'

       Wir kA<paragraph>nnen ebenso die	Funktion $rdr->value benutzen um die
       gleichen	Daten zu erhalten:

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

	 # Die folgenden drei Alternativen sind	gleichwertig:
	 # --------------------------------------------------
	 #   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";

       Das is das Ergebnis:

	 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>

       Es ist hier zu Bemerken dass der	Fall "root3" / "output1" { root	=>
       'p', branch => '*' } beweist dass immer der grA<paragraph>sst
       mA<paragraph>glichste XML-Baum fA1/4r einen relativen Pfad gewAxhlt
       wird. Oder anders ausgedrA1/4ckt: die Ausgabe von "P: <p>b1</p>"	and
       "P: <p>b2</p>" auf separaten Zeilen ist nicht mA<paragraph>glich	da
       diese UnterbAxme	schon in dem grA<paragraph>sseren Baum "P:
       <p><p>b1</p><p>b2</p></p>" enthalten sind.

OPTION DUPATT
       Die Option dupatt erlaubt es mehrere Attribute mit gleichem Namen zu
       einem einzigen Ergebnis zusammenzufassen.  Um dieses zu
       ermA<paragraph>glichen, werden die verschiedenen	Werte zu einem
       einzigen	Wert und durch ein spezielles Trennzeichen verbunden. Die
       Attributliste wird in diesem Falle alphabetisch sortiert	ausgegeben.

       Die Option dupatt ist nur dann mA<paragraph>glich wenn XML::Reader mit
       der Option XML::Parsepp eingebunden wurde.

       Das folgende Beispiel zeigt die Verwendung der Option dupatt: (Der
       Verbindungs String {dupatt => $str} ist begrenzt	auf druckbare Ascii-
       Zeichen ausser alphanumerische Zeichen, " oder ')

	 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;
	 }

       Dieses Programm erzeugt die folgende Ausgabe:

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

BEISPIELE
       Betrachten wir nun folgende XML-Datei, von der wir die Werte innerhalb
       der Tags	<item> (dabei meine ich	nur den	ersten Teil 'start...',	und
       nicht den zweiten Teil 'end...')	plus die Attribute "p1"	und "p3"
       extrahieren wollen. Der <item>-Tag muss exact im	Pfad /start/param/data
       existieren (und *nicht* im Pfad /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>};

       Wir erwarten genau 4 Ergebnis-Zeilen von	unserem	Parse-Lauf (d.h. wir
       erwarten	keine 'dataz' -	'start9' Werte):

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

   Beispiel XML	filter 2 mode attr-bef-start
       Hier ist	ein Beispiel-Programm um die XML-Datei mit {filter => 2, mode
       => 'attr-bef-start'} zu parsen. (Bitte beachten Sie wie der PrAxfix
       '/start/param/data/item'	in der {using => ...} Option von new verwendet
       wird). Wir brauchen ausserdem zwei scalar Variablen ('$p1' und '$p3')
       um die Parameter	in '/@p1' und '/@p3' aufzunehmen und sie in den
       Programmteil $rdr->is_start zu A1/4bertragen, wo	sie dann ausgegeben
       werden kA<paragraph>nnen.

	 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;	}
	 }

   Beispiel filter 3 mode attr-in-hash
       Mit {filter => 3, mode => 'attr-in-hash'} kA<paragraph>nnen wir auf die
       zwei scalar Variablen ('$p1' und	'$p3') verzichten, das Programm
       vereinfacht sich	wie folgt:

	 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};
	     }
	 }

   Beispiel filter 4 mode pyx
       Jedoch mit {filter => 4,	mode =>	'pyx'} wird das	Programm wieder
       komplizierter: Wie schon	im Beispiel fA1/4r {filter => 2, mode =>
       'attr-bef-start'} gezeigt, benA<paragraph>tigen wir hier	wieder zwei
       scalar Variablen	('$p1' und '$p3') um die Parameter in '/@p1' und
       '/@p3' aufzunehmen und sie dann zu A1/4bertragen. ZusAxtzlich mA1/4ssen
       wir hier	jedoch auch noch Text-Werte zAxhlen kA<paragraph>nnen (siehe
       scalar Variable '$count'), sodass wir zwischen dem ersten Wert
       'start...' (welchen wir ausgeben	wollen)	und dem	zweiten	Wert 'end...'
       (welchen	wir nicht ausgeben wollen) unterscheiden kA<paragraph>nnen.

	 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;
		     }
		 }
	     }
	 }

   Beispiel filter 5 mode branches
       Sie kA<paragraph>nnen {filter =>	5, mode	=> 'branches'} und regulAxre
       AusdrA1/4cke lombinieren:

	 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;
	     }
	 }

   Beispiel Attribut Bedingungen
       Wir betrachten nun ein weiteres Beispiel	($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>
	 };

       Jetzt kann man in den Pfaden (root => ... and branch => ...) Attribut
       Bedingungen hinzufA1/4gen ('/path1[@attr="val"]/...'), z.B.:

	 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;
	 }

       Das Ergebnis sieht wie folgt aus:

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

FUNKTIONEN
   Funktion slurp_xml
       Die Funktion slurp_xml liest eine XML Datei und legt die	Daten in einer
       Array-Referenz ab. Hier ist ein Beispiel	in dem wir den Namen, die
       Strasse und die Stadt fA1/4r alle Kunden	im Pfad
       '/data/order/database/customer' erhalten	wollen.	Wir wollen ausserdem
       alle Supplier im	Pfad '/data/supplier' erhalten:

	 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", $_;
	 }

       Der erste Parameter in slurp_xml	ist entweder der Dateiname (oder eine
       Skalar Referenz,	oder ein offenes Dateihandle) der XML Datei die	wir
       einlesen	wollen.	In diesem Fall lesen wir von der Skalar	Referenz
       \$line2.	 Der nAxchste Parameter	ist die	Wurzel des Baumes den wir
       einlesen	wollen (in diesem Falle	wAxre das
       '/data/order/database/customer')	mit einer Liste	von Elementen die wir,
       relativ zur Wurzel, selektieren wollen, in diesem Falle wAxre das
       ['@name', 'street', 'city']. Der	darauffolgende Parameter ist eine
       zweite Wurzel (root/branch Definition), in diesem Falle ist es root =>
       '/data/supplier'	mit branch => ['/'].

       Hier ist	das Resultat:

	 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>

       slurp_xml funktioniert Axhnlich wie XML::Simple,	insofern als dass alle
       benA<paragraph>tigten Informationen in einem Rutsch in einer
       Speicherstruktur	abgelegt werden. Der Unterschied jedoch	ist dass
       slurp_xml uns erlaubt spezifische Daten zu selektieren bevor das
       Einlesen	beginnt. Dieses	hat zur	Folge dass die sich ergebende
       Speicherstruktur	meistens kleiner ist, und damit	auch weniger
       kompliziert.

       Man kann	slurp_xml auch beauftragen doppelte Attribute zu verwalten. In
       diesem Falle muss man zwei Dinge	beachten: Erstens muss man ein "use
       XML::Reader" mit	folgenden optionen: "qw(XML::Parsepp slurp_xml)"
       ausfuehren. Zum zweiten muss man	slurp_xml mit der option { dupatt =>
       '|' } aufrufen, wie das folgende	Beispiel belegt:

	 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";

       Hier ist	das Ergebnis:

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

AUTOR
       Klaus Eichner, March 2009

COPYRIGHT UND LIZENZ
       Dieses ist der original Text auf	Englisch:

       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

VERWANDTE MODULE
       Falls Sie vorhaben XML auch ausgeben zu wollen, dann schlage ich	vor
       eines der zwei Module XML::Writer oder XML::MinWriter zu	benutzen.
       Beide Module bieten ein einfach zu handhabendes Interface zur Ausgabe
       von XML-Dateien.	 (Falls	sie non-mixed content XML ausgeben, wA1/4rde
       ich empfehlen die Optionen DATA_MODE=>1 und DATA_INDENT=>2 zu setzen,
       das erlaubt die korrekte	Formatierung und EinrA1/4ckung in Ihrer	XML
       Ausgabe-Datei).

REFERENZEN
       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_de(3)

NAME | ~ | SYNOPSIS | BENUTZUNG | BESCHREIBUNG | INTERFACE | OPTION USING | OPTION PARSE_CT | OPTION PARSE_PI | OPTION FILTER / MODE | OPTION DUPATT | BEISPIELE | FUNKTIONEN | AUTOR | COPYRIGHT UND LIZENZ | VERWANDTE MODULE | REFERENZEN

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

home | help