Naťukněme stručně několik témat souvisejících s XML. Bude to jen úvod, ze kterého by mělo vycházet další studium.
10.7.2011 00:00 | Jiří Václavík | přečteno 10845×
Představme si velmi stručně ještě jeden z nejlepších modulů pro práci s XML, kterým je XML::LibXML od českého autora Petra Pajase. Umí parsovat XML soubory jako DOM. DOM je aplikační rozhraní pro čtení nebo zápis obsahu a struktury XML dokumentů.
Opět budeme pracovat se souborem ukazka.xml.
<?xml version="1.0" encoding="UTF-8"?>
<katalog>
<kniha id="1">
<nazev>Stopařův průvodce Galaxií 1.</nazev>
<autor>Adams Douglas</autor>
<foto src="stoparuv.jpg" alt="Titulní strana - Stopařův průvodce"/>
<popis>
Nezapomeňte: <citace>ručník je dost možná tou nejužitečnější věcí ve vesmíru</citace>.
</popis>
<cena>319</cena>
</kniha>
<kniha id="2">
<nazev>Alchymista</nazev>
<autor>Coelho Paulo</autor>
<foto src="alchymista.jpg" alt="Titulní strana - Alchymista"/>
<popis>
Cesta za pokladem.
</popis>
<cena>399.90</cena>
</kniha>
</katalog>
Následující kód parsuje soubor ukazka.xml a načte data do objektu.
use XML::LibXML;
$parser = XML::LibXML->new;
$d = $parser->parse_file("ukazka.xml");
Pro opětovný výpis dat ve formátu XML nyní budeme volat metodu toString.
print $d->toString(1);
Velmi stručně se podívejme, jak přidávat nové elementy. Budeme k tomu potřebovat odkaz na kořenový element.
$root = $doc->documentElement();
Přidejme nejprve další knihu.
$kniha = $root->addNewChild("", "kniha");
Poté dovnitř můžeme přidat elementy pro autora a název.
$autor = $kniha->addNewChild("", "autor");
$nazev = $kniha->addNewChild("", "nazev");
Do těchto elementů již můžeme vepsat data.
$autor->addChild($doc->createTextNode("Antoine de Saint-Exupéry"));
$nazev->addChild($doc->createTextNode("Malý princ"));
Pro další podobné metody lze nahlédnout do dokumentace.
Modul XML::LibXML je velmi komplexní a umí obrovské množství věcí. Pro zájemce je k dispozici dokumentace.
Ještě se stručně podívejme, jak lze pracovat s nástrojem SAX. Ten nabízí trochu odlišný přístup na XML dokument. SAX chápe XML jako tok dat a událostí. Každý element vyvolá příslušnou událost a na základě nich postupně můžeme zpracovávat data.
XML::LibXML má SAX rozhraní, avšak je pouze simulované, protože data jsou tak jako tak načteny do paměti. Je třeba se poohlédnout zase po něčem novém. Podívejme se blíže na XML::SAX::ExpatXS.
use XML::SAX::ParserFactory;
use XML::SAX::Writer;
$XML::SAX::ParserPackage = "XML::SAX::ExpatXS";
$parser = XML::SAX::ParserFactory->parser(Handler => XML::SAX::Writer->new);
$parser->parse_file("ukazka.xml") ;
Na programátorovi je určit ke každé události, jak se na ni má reagovat. My jsme v příkladu použili standardní XML::SAX::Writer, který vypíše na výstup XML.
Rozšiřováním XML::SAX::Base pomocí navrhování handlerů můžeme definovat vlastní reagování na události. Funguje to tak, že přetížíme některé z metod, které jsou uvedené v dokumentaci. Zkusme přetížit metodu start_element, která je volána vždy poté, kdy narazíme na první z páru elementů. Můžeme pomocí SUPER zdědit chování nadřízené třídy nebo nějak jinak manipulovat s daty.
package MujHandler;
use Data::Dumper;
use base qw(XML::SAX::Base);
sub start_element {
my ($self, $data) = @_;
$self->SUPER::start_element($data);
}
#další metody
1;
Stojí za to se podívat, co vlastně v proměnné $data máme.
print Dumper $data;
Podívejme se orientačně, jak vypadá výstup pro elementy autor a foto.
$VAR1 = {
'LocalName' => 'autor',
'Prefix' => '',
'Attributes' => {},
'Name' => ${\$VAR1->{'LocalName'}},
'NamespaceURI' => ${\$VAR1->{'Prefix'}}
};
$VAR1 = {
'LocalName' => 'foto',
'Prefix' => '',
'Attributes' => {
'{}alt' => {
'LocalName' => 'alt',
'Prefix' => ${\$VAR1->{'Prefix'}},
'Value' => "Tituln\x{ed} strana - Stopa\x{159}\x{16f}v pr\x{16f}vodce",
'Name' => ${\$VAR1->{'Attributes'}{'{}alt'}{'LocalName'}},
'NamespaceURI' => ${\$VAR1->{'Prefix'}}
},
'{}src' => {
'LocalName' => 'src',
'Prefix' => ${\$VAR1->{'Prefix'}},
'Value' => 'stoparuv.jpg',
'Name' => ${\$VAR1->{'Attributes'}{'{}src'}{'LocalName'}},
'NamespaceURI' => ${\$VAR1->{'Prefix'}}
}
},
'Name' => ${\$VAR1->{'LocalName'}},
'NamespaceURI' => ${\$VAR1->{'Prefix'}}
};
Abychom si také ukázali nějaký příklad vlastního handleru, zkusíme vypsat stromový seznam všech otevíracích a uzavíracích elementů.
Jak tedy bude vypadat náš handler? Vytvoříme dvě metody - jednu pro otevírací elementy a druhou pro uzavírací. Z proměnné $data získáme snadno název elementu. Také budeme uchovávat hloubku zanoření.
package MujHandler;
use Data::Dumper;
use base qw(XML::SAX::Base);
our $zanoreni = 0;
sub start_element {
my ($self, $data) = @_;
print " " x $zanoreni . $$data{"LocalName"}." - zacatek elementu\n";
$zanoreni++;
}
sub end_element {
my ($self, $data) = @_;
$zanoreni--;
print " " x $zanoreni . $$data{"LocalName"}." - konec elementu\n";
}
1;
Nyní tento handler použijeme. V úvodním programu nahradíme XML::SAX::Writer za náš MujHandler.
use XML::SAX::ParserFactory;
use MujHandler;
my $handler = MujHandler->new();
$XML::SAX::ParserPackage = "XML::SAX::ExpatXS";
my $parser = XML::SAX::ParserFactory->parser(Handler => $handler);
$parser->parse_uri("ukazka.xml") ;
A výsledek?
katalog - zacatek elementu
kniha - zacatek elementu
id - zacatek elementu
id - konec elementu
nazev - zacatek elementu
nazev - konec elementu
autor - zacatek elementu
autor - konec elementu
foto - zacatek elementu
foto - konec elementu
popis - zacatek elementu
citace - zacatek elementu
citace - konec elementu
popis - konec elementu
cena - zacatek elementu
cena - konec elementu
kniha - konec elementu
kniha - zacatek elementu
id - zacatek elementu
id - konec elementu
nazev - zacatek elementu
nazev - konec elementu
autor - zacatek elementu
autor - konec elementu
foto - zacatek elementu
foto - konec elementu
popis - zacatek elementu
popis - konec elementu
cena - zacatek elementu
cena - konec elementu
kniha - konec elementu
katalog - konec elementu
Nyní si lze snadno představit, jak přizpůsobivý nástroj máme.