Document
,
Element
, Texte
Document
,Document
. Element
: c'est l'espèce des sommets
de
l'arbre qui correspondent aux balises dans le texte XML.Element
possède un nom (celui de la balise),
des attributs et des enfants.Document
contient un Element
particulier
qui est la racine de l'arbre XML Text
: c'est l'espèce des objets qui
représentent les contenus textuels qui apparaissent entre les balises.Text
sera toujours enfant d'un Element
,
tandis que lui-même
n'aura ni attribut ni enfant, Voiture.xml
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="Voiture.css"?>
<!DOCTYPE Voiture SYSTEM "Voiture.dtd" >
<Voiture marque="Renault" modèle="Safrane">
<Carosserie couleur="rouge">
<Capot>Un peu cabossé</Capot>
</Carosserie>
<Moteur>
<Cylindres />
<Allumage>Défectueux</Allumage>
</Moteur>
<Transmission type="automatique" nb_vitesses="5">
<Boîte />
<TrainAV />
<TrainAR />
</Transmission>
</Voiture>
Document
, 10 Element
s et 2 Text
s.Document
.my $parseur = XML::DOM::Parser->new();
my $doc = $parseur->parsefile("Voiture.xml");
Element
-racine par la méthode getDocumentElement()
my $voiture = $doc->getDocumentElement();
Element
.getNodeName()
my $nom =
$voiture->
getNodeName()
;
getAttribute(le-nom)
my $marque = $voiture->getAttribute("marque");
my $modele = $voiture->
getAttribute("mod\x{00E8}
le");
getChildNodes()
my @cmt = $voiture->getChildNodes();
foreach my $enf ( @cmt ){
print ($enf->getNodeName());
}
getChildNodes()
nous donne tous
les enfants de l'Element
concerné.Element
est entouré
par deux objets Text.
La boucle ci-dessus donne :#text Carosserie #text Moteur #text
Transmission #text
Text
.Text
n'est pas une
chaîne de caractères !Text
est une "boîte" qui contient une chaîne.getData()
pour avoir
la chaîne.Element
ne contenant
que du texte (comme Capot
et Allumage
dans
l'exemple ci-dessus)Text
est alors son unique enfant, on l'obtient
directement par getFirstChild()
.my $carosserie = $cmt[1]; # après l'indentation
my @caps = $carosserie->getChildNodes();
my $capot = $caps[1]; # idem
my $txt = $capot->
getFirstChild(); # capot est une
feuille
my $chn = $txt->getData();
voiture1.pl
use
strict;
use warnings;
use XML::DOM;
# le fichier sera lu automatiquement en UTF-8,
# on prépare les impressions sur la sortie standard
binmode(STDOUT, ":utf8");
my $parseur = XML::DOM::Parser->new();
my $doc = $parseur->parsefile("Voiture.xml");
my $voiture = $doc->getDocumentElement();
my $nom = $voiture->getTagName();
print("$nom\n");
my $marque = $voiture->getAttribute("marque");
my $modele = $voiture->getAttribute("mod\x{00E8}le");
print("$marque $modele\n");
my @cmt = $voiture->getChildNodes();
foreach my $enf ( @cmt ){
print ($enf->getNodeName());
print(" ");
}
print("\n");
my $carosserie = $cmt[1]; # après le saut de ligne
my @caps = $carosserie->getChildNodes();
foreach my $cap ( @caps ){
print ($cap->getNodeName());
print(" ");
}
print("\n");
my $capot = $caps[1]; # idem
my $txt = $capot->getFirstChild(); # capot est une feuille
my $chn = $txt->getData();
print("$chn\n");
jfp% perl voiture1.pl
Voiture
Renault Safrane
#text Carosserie #text Moteur #text Transmission #text
#text Capot #text
Un peu cabossé
jfp%
Node
Document
, Element
et Text
appartiennent toutes au même genre, appelé Node
.getChildNodes()
est une liste de
d'objets Node
, contenant aussi bien des Element
que des Text
.Element
et à un Text
!getData()
à un Element
,
ni getAttribute(...)
à un Text
...getNodeName()
peut être demandée à
toute espèce de Node
.Element
elle renvoie son nom, pour un Text
elle renvoie la chaîne fixe "#text
".#
'
est interdit dans une balise.]getTagName()
pour un Element
seulement.foreach my $enf ( @cmt ){
if(
getNodeName()
ne '#text' ){
print (
$enf->getTagName()
);
}else{
print (
$enf->getData()
);
}
}
Voiture.xml
nous suggère
de mettre à part les objets Text
s parasitesNode
, va
répondre vrai si cet objet n'est pas un Text
parasite.sub nonVide($){ # arg. Node
my ($node) = @_;
return ($node->getNodeName() ne '#text') ||
($node->getData() !~ /^\s*/$);
}
Element
$voiture
sont bien des Element
s :my @cmt = $voiture->getChildNodes();
foreach my $enf ( @cmt ){
if( nonVide($enf) ){
print
($enf->getTagName());
}
}
getElementsByTagName(un-nom)
Element
s
:Element
ou à un Document
, getElementsByTagName(un-nom)
va renvoyer Element
s et portent le nom
passé en paramètre Element
s de
même nom sont tous des successeurs d'un même sommet,my ($var) = $l-element->getElementsByTagName(un-nom);
my ($capot) = $voiture->getElementsByTagName("Capot");
getChildNodes
,
et à un parcours attentif à la nature des enfants,
voiture2.pl
use strict;
use warnings;
use XML::DOM;
binmode(STDOUT, ":utf8");
sub nonVide($){ # arg. Node
my ($node) = @_;
return ($node->getNodeName() ne '#text') ||
($node->getData() !~ /^\s*$/);
}
my $parseur = XML::DOM::Parser->new();
my $doc = $parseur->parsefile("Voiture.xml");
my $voiture = $doc->getDocumentElement();
my $nom = $voiture->getTagName();
print("$nom\n");
my $marque = $voiture->getAttribute("marque");
my $modele = $voiture->getAttribute("mod\x{00E8}le");
print("$marque $modele\n");
my @cmt = $voiture->getChildNodes();
foreach my $enf ( @cmt ){
if( nonVide($enf) ){
print
($enf->getTagName());
print(" ");
}
}
print("\n");
my ($capot) = $voiture->getElementsByTagName("Capot");
my $chn = $capot->getFirstChild()->getData(); # abrégeons !
print("Capot : $chn\n");
jfp% perl voiture2.pl
Voiture
Renault Safrane
Carosserie Moteur Transmission
Capot : Un peu cabossé
jfp%
Utilisation de getElementsByTagName(...)
sur des
documents bien structurés.
Ex1.xml
<?xml version="1.0" ?>
<liste>
<eleve nom="Pierre" note="12"/>
<eleve nom="Paul" note="13"/>
<eleve nom="Jacques" note="17"/>
</liste>
Lire_1.pl
use strict;
use warnings;
use XML::DOM;
sub lire_1 ($) { #Document -> flottant
my ($doc) = @_;
my $liste = $doc->getDocumentElement();
my $k = 0; #nombre de notes
my $s = 0; #le total des notes
my @les_eleves =
$liste->getElementsByTagName("eleve");
foreach my $l_eleve ( @les_eleves ){
#lecture
my $le_nom =
$l_eleve->getAttribute("nom");
my $la_note =
$l_eleve->getAttribute("note");
#action
print("$le_nom a pour note
$la_note\n");
$s += $la_note;
$k++;
}# foreach
if( $k == 0 ){
die("fichier vide");
}else{
return $s/$k;
}
}# lire_1
sub lecture ($){# nom de fichier
my ($fichIn) = @_;
my $parseur = XML::DOM::Parser->new();
my $doc = $parseur->parsefile($fichIn);
my $moy = lire_1($doc);
print("\nMoyenne : $moy\n");
}#lecture
lecture($ARGV[0]);
fp% perl Lire_1.pl Ex1.xml
Pierre a pour note 12
Paul a pour note 13
Jacques a pour note 17
Moyenne : 14
jfp%
Ex2.xml
<?xml version="1.0" ?>
<liste>
<eleve>
<nom> Toto</nom> <note> 12
</note>
</eleve>
<eleve>
<nom> Tata</nom> <note> 13
</note>
</eleve>
<eleve>
<nom> Tutu</nom> <note> 17
</note>
</eleve>
</liste>
Lire_2.pl
use strict;
use warnings;
use XML::DOM;
sub lire_2 ($) { #Document -> flottant
my ($doc) = @_;
my $liste = $doc->getDocumentElement();
my $s = 0; #le total des notes
my @les_eleves =
$liste->getElementsByTagName("eleve");
my $k = @les_eleves; # longueur de la liste
(évaluation "en contexte scalaire")
foreach my $l_eleve ( @les_eleves ){
#lecture
my ($elt_nom) =
$l_eleve->getElementsByTagName("nom");
my $le_nom =
$elt_nom->getFirstChild()->getData();
my ($elt_note) =
$l_eleve->getElementsByTagName("note");
my $la_note =
$elt_note->getFirstChild()->getData();
#action
print("$le_nom a pour note
$la_note\n");
$s += $la_note;
}# foreach
if( $k == 0 ){
die("fichier vide");
}else{
return $s/$k;
}
}# lire_2
sub lecture ($){# nom de fichier
my ($fichIn) = @_;
my $parseur = XML::DOM::Parser->new();
my $doc = $parseur->parsefile($fichIn);
my $moy = lire_2($doc);
print("\nMoyenne : $moy\n");
}#lecture
lecture($ARGV[0]);
fp% perl Lire_2.pl Ex2.xml
Toto a pour note 12
Tata a pour note 13
Tutu a pour note 17
Moyenne : 14
jfp%
Neruda.pl
use strict;
use warnings;
use XML::DOM;
# La structure
sub printPoema($){ #arg. Element "poema"
my ($poema) = @_;
my ($titre) =
$poema->getElementsByTagName("t\x{00ED}tulo");
printTitre($titre->getFirstChild()->getData());
my @estrofas =
$poema->getElementsByTagName("estrofa");
foreach my $estrofa ( @estrofas ){
printEstrofa($estrofa);
printFinStrofa();
}
}#printPoema
sub printEstrofa($){ #arg. Element "estrofa"
my ($str) = @_;
my @versos = $str->getElementsByTagName("verso");
foreach my $verso ( @versos ){
print($verso->getFirstChild()->getData());
printFinVerso();
}
}#printEstrofa
# Choix typographiques
sub printTitre($){ # arg. chaîne
my ($chn) = @_;
print("<h2>$chn</h3>\n");
}
sub printFinVerso(){
print("<br />\n");
}
sub printFinStrofa(){
print("<hr />\n");
}
# Exécution
sub lecture ($){# nom de fichier
my ($fichIn) = @_;
my $parseur = XML::DOM::Parser->new();
my $doc = $parseur->parsefile($fichIn);
binmode(STDOUT, ":utf8");
print(
'<html><head><meta content="text/html; charset=UTF-8"
http-equiv="content-type" />
<title>FromXML</title></head><body>'
);
printPoema ($doc->getDocumentElement());
print("</body></html>\n");
}#lecture
lecture($ARGV[0]);
getChildNodes
sur des documents mal ou peu
structurés.L922.xml
,
qui contient les Odes funambulesques de Théodore de Banville :<div>
<head>ÉCRIT SUR 1 EXEMPLAIRE ODELETTES</head>
<pb n="237"/>
<p>quand j'ai fait ceci,<lb/>
moi que nul souci<lb/>
ne ronge,<lb/>
la fièvre de l'or<lb/>
nous tenait encor :<lb/>
j'y songe !<lb/>
Pendant ces moments,<lb/>
comme les romans<lb/>
que fonde<lb/>
le joyeux About,<lb/>
elle avait pris tout<lb/>
le monde !<pb n="238"/>
Vous rappelez-vous<lb/>
les efforts jaloux,<lb/>
les brigues,<lb/>
les peurs, les succès ?<lb/>
Le combat eut ses<lb/>
Rodrigues !<lb/>
Oh ! Qu'il fut ardent,<lb/>
hélas ! Moi pendant<lb/>
la lutte<lb/>
et son bruit d'enfer,<lb/>
j'essayais un air<lb/>
de flûte !<lb/>
<hi rend="I"> juin 1858 : </hi></p>
</div>
<div>
,
laquelle contient <head>
avec le titre<p>
avec le texte, sur le modèle
ci-dessus.Text
qu'on devra aller chercher parmi les ChildNodes
de l'Element
p
,Text
, et
des Element
s lb
, pb
et hi
.getElementsByTagName
et de revenir à la technique minutieuse présentée à la section III.LireTEI-1.pl
use strict;
use warnings;
use XML::DOM;
sub printDoc($){ #Document
my ($doc) = @_;
my @listDivs =
$doc->getDocumentElement()->getElementsByTagName("div");
foreach my $div ( @listDivs ){
printDiv($div);
}
}#printDoc
sub printDiv($){ # objet "div"
my ($div) = @_;
my ($head) =
$div->getElementsByTagName("head");
print($head->getFirstChild()->getData());
print(" : ".nbVers($div)." vers.\n");
}#printDiv
sub nbVers($){ # objet "div"
my ($div) = @_;
my $k =0; # le compteur de vers
my ($txt) = $div->getElementsByTagName("p");
my @enfs = $txt->getChildNodes();
foreach my $enf ( @enfs ){
if( $enf->getNodeName()
eq '#text' ){ # c'est un vers
$k++;
}
}
return $k;
}# nbVers
# Exécution
sub lecture ($){# nom de fichier
my ($fichIn) = @_;
my $parseur = XML::DOM::Parser->new();
my $doc = $parseur->parsefile($fichIn);
binmode(STDOUT, ":utf8");
printDoc ($doc);
}#lecture
lecture($ARGV[0]);
jfp% perl LireTEI-1.pl L922.xml
LA CORDE ROIDE : 61 vers.
LA VILLE ENCHANTÉE : 108 vers.
LA BELLE VÉRONIQUE : 53 vers.
VARIATIONS LYRIQUES : 201 vers.
PREMIER SOLEIL : 45 vers.
LA VOYAGEUSE : 127 vers.
éVOHé, NéMéSIS INTéRIMAIRE : 1087 vers.
LES FOLIES NOUVELLES : 582 vers.
OCCIDENTALES : 970 vers.
RONDEAUX : 100 vers.
TRIOLETS : 186 vers.
à 1 AMI POUR PRIX TRAV. LITTéR. : 49 vers.
VILLANELLE DE BULOZ : 26 vers.
ÉCRIT SUR 1 EXEMPLAIRE ODELETTES : 25 vers.
VILLANELLE DES PAUVRES HOUSSEURS : 38 vers.
CHANSON SUR L'AIR DES LANDRIRY : 121 vers.
BALLADE CéLéBRITéS TEMPS JADIS : 29 vers.
VIRELAI à MES éDITEURS : 57 vers.
BALLADE DES TRAVERS DE CE TEMPS : 38 vers.
MONSIEUR COQUARDEAU, CHANT ROYAL : 64 vers.
MONSELET D'AUTOMNE, PANTOUM : 41 vers.
RÉALISME : 78 vers.
MÉDITATION POÉTIQUE LITTÉRAIRE : 28 vers.
MA BIOGRAPHIE À HENRI D'IDEVILLE : 49 vers.
À AUGUSTINE BROHAN : 37 vers.
LA SAINTE BOHÈME : 71 vers.
BALLADE DE LA VRAIE SAGESSE : 37 vers.
LE SAUT DU TREMPLIN : 62 vers.
jfp%
LireTEI-2.pl
use strict;
use warnings;
use XML::DOM;
sub printDoc($$){ #Document, fragment de titre
my ($doc, $frag) = @_;
my @listDivs =
$doc->getDocumentElement()->getElementsByTagName("div");
foreach my $div ( @listDivs ){
my ($head) =
$div->getElementsByTagName("head");
my $titre =
$head->getFirstChild()->getData();
if( $titre =~
m/$frag/ ){
printTitre($titre);
printDiv($div);
return;
}
}
print("Je n'ai pas trouv\x{00E9} de titre contenant
'$frag'\n");
}#printDoc
sub printDiv($){ # objet "div"
my ($div) = @_;
my ($par) = $div->getElementsByTagName("p");
my @cont = $par->getChildNodes();
foreach my $frag ( @cont ){
my $indic =
$frag->getNodeName();
if( $indic eq 'lb' ||
$indic eq 'pb'){
printFinLigne();
}elsif( $indic eq '#text' ){
my $chn
= $frag->getData();
$chn =~
s/^\s*(\S*)/$1/; # supprime un saut de ligne initial
print(
$chn );
}else{
# hi, ne rien faire
}
}
}#printDiv
sub printTitre($){ # arg. chaine
my ($txt) = @_;
print("***$txt***\n")
}#printTitre
sub printFinLigne(){
print("\n");
}
# Exécution
sub lecture ($$){# nom de fichier, fragment de titre
my ($fichIn, $frag) = @_;
my $parseur = XML::DOM::Parser->new();
my $doc = $parseur->parsefile($fichIn);
binmode(STDOUT, ":utf8");
printDoc ($doc, $frag);
}#lecture
lecture($ARGV[0], $ARGV[1]);
jfp% perl LireTEI-2.pl L922.xml EXEMPLAIRE
***ÉCRIT SUR 1 EXEMPLAIRE ODELETTES***
quand j'ai fait ceci,
moi que nul souci
ne ronge,
la fièvre de l'or
nous tenait encor :
j'y songe !
Pendant ces moments,
comme les romans
que fonde
le joyeux *About,
elle avait pris tout
le monde !
Vous rappelez-vous
les efforts jaloux,
les brigues,
les peurs, les succès ?
Le combat eut ses
*Rodrigues !
Oh ! Qu'il fut ardent,
hélas ! Moi pendant
la lutte
et son bruit d'enfer,
j'essayais un air
de flûte !
jfp% perl LireTEI-2.pl L922.xml SOLAILLE
Je n'ai pas trouvé de titre contenant 'SOLAILLE'
jfp%