INaLCO - M2 Traductique
Introduction à XML
Jean-François
Perrot
DOM (Document Object
Model) - 2 :
Construction
Version en PHP
- Principe
de la
construction en DOM
- Construire
un
objet Document en mémoire
plutôt qu'écrire dans un fichier
- Rôle
prééminent
de l'objet DOMDocument
- Création
d'objets des
trois espèces Document, Element
et Text
- Création
(et sortie sur fichier) de l'objet DOMDocument
- Création
et
équipement d'un l'objet Element
- Création
d'un
l'objet DOMText
- Récapitulation
- Exemple
: construire un fichier XML de noms & notes à partir de
fichiers-texte
- Syntaxe
du
fichier-texte (source)
- Syntaxe (DTD) du fichier XML (but)
- Construction de la représentation
1 (par attributs)
- Représentation
2 (par enfants)
- Variation : modifier un DOMDocument
-
-
Il est toujours possible de créer un fichier XML en écrivant son
texte-contenu, caractère par caractère.
C'est ce que nous avons fait au
cours précédent pour produire un fichier HTML à
partir d'un fichier contenant un poème.
Cette manière de faire, simple dans son principe, a le grave
inconvénient d'être sujette à l'erreur (en anglais error-prone).
En effet, l'acte élémentaire de création d'un sommet de l'arbre se
réalise comme une succession de trois opérations,
- écriture de la balise ouvrante et de ses attributs ;
- écriture du contenu - qui peut être compliquée ;
- écriture de la balise fermante.
Il est fort difficile d'assurer que ces trois opérations sont bien
exécutées sans faute, dans le bon ordre ...
La technique DOM offre le moyen de séparer
- la construction en mémoire d'un objet
Document
,
de manière globale et synthétique
- et son écriture dans un fichier, de manière
séquentielle
(dans le jargon des informaticiens, cette opération s'appelle sérialisation).
Même si elle peut sembler pesante, cette façon de faire est clairement
préférable, car beaucoup plus facile à vérifier.
-
Construire un
DOMDocument
implique
évidemment de
construire ses parties : élements, attributs et textes.
D'une manière analogue à ce qui se passe dans la construction d'un
bâtiment préfabriqué, les choses se passent en 2 temps :
- Création de l'objet (par
exemple un objet
DOMElement
)
-
qui a lieu, pour ainsi dire, en atelier, hors de son contexte
d'utilisation ;
- Mise en place de l'objet dans
l'arbre en
construction,
en d'autres termes, insertion de l'objet dans son contexte
d'utilisation.
Comme toujours en programmation par objets, chaque phase sera effectuée
en envoyant un ordre à un objet.
- La seconde phase est sans mystère :
la mise en place d'un objet dans l'arbre est toujours vue comme
l'adjonction d'un fils à un père préexistant
(en somme, comme une naissance dans une famille)
et jamais comme l'imposition d'un nouveau père à un enfant déjà
installé.
On demande donc à l'objet-père d'accueilir ce nouvel enfant...
La forme la plus fréquente de cette demande est appendChild(l-enfant)
,
qui respecte l'ordre des dates de naissance.
- La première en revanche est plus délicate : quel
objet va
jouer le rôle de l'atelier de fabrication ?
Ce sera l'objet Document
lui-même !
Plus précisément :
les objets destinés à prendre place dans l'arbre
d'un DOMDocument
doivent être créés par ce Document
-même.
D'où il résulte que l'objet DOMDocument
doit
être créé par
d'autres moyens... Voir ci-après.
-
illustrée sur l'exemple Voiture.
-
-
DOMDocument
vide
En PHP, il suffit de demander la création d'un document vide à la
classe DOMDocument
elle-même :
$doc = new DOMDocument();
On obtient ainsi un DOMDocument
sans
feuille de style ni DTD.
Contrairement à l'arbre XML, ces appendices ne pouront pas être ajoutés
par la suite.
Si on souhaite en faire usage, il faut recourir à un processus de
création plus compliqué, en passant par un objet DOMImplementation
.
- Racine de l'arbre XML
En PHP, c'est un DOMElement
comme les autres
:
on le crée et on le met en place
$voiture =
$doc->createElement('Voiture');
$doc->appendChild($voiture);
- Sortie sur fichier
En PHP : $doc->save(nom-du-fichier);
Si on souhaite obtenir la chaîne de caractères
(contenu du fichier), demander
$chn = $doc->saveXML();
-
- Création par
$doc->createElement(le-nom);
où $doc
est le DOMDocument
qui
contiendra le DOMElement
ainsi créé.
- Insertion d'attributs par
setAttribute(le-nom,
la-valeur)
$voiture->setAttribute('marque',
"Citroen");
$voiture->setAttribute("modele", 'AX');
- Ajout d'un enfant (à la suite
de ses aînés) par
appendChild(l-enfant)
- Mode opératoire : pour éviter
les oublis...
on procèdera systématiquement ainsi :
- création :
$carosse = $doc->createElement('Carosserie');
- accrochage immédiat, le
DOMElement
créé étant encore vide...:
$voiture->appendChild($carosse);
N.B. l'objet créateur est $doc
,
ce n'est pas le
père, qui est $voiture
...
DOM ne se conforme pas aux lois de la Nature !
- remplissage du nouveau sommet de l'arbre :
my $capot =
$doc->createElement('Capot');
$carosse->appendChild($capot);
etc.
-
- Création par
$doc->createTextNode(le-contenu);
où $doc
est le DOMDocument
qui
contiendra le DOMText
ainsi créé.
- Pratique courante : construction d'un
DOMElement
-feuille.
On crée et on met en en place (comme enfant de son père) le DOMElement
en question,
par exemple notre $capot
,
et on lui attribue comme "premier enfant" un objet DOMText
créé
"au vol" :
$capot->appendChild($doc->createTextNode('Impeccable
!'));
-
Construction d'une nouvelle
Voiture
...
fichier consVoiture.php
<?php
// Construction d'un document XML de type Voiture
// Le DOMDocument
$doc = new DOMDocument();
$voiture = $doc->createElement('Voiture');
$doc->appendChild($voiture);
// L'arbre XML
//1. Les attributs de 'Voiture'
$voiture->setAttribute('marque', "Citroen");
$voiture->setAttribute("modele", 'AX');
//2. La carosserie et son capot
$carosse = $doc->createElement('Carosserie');
$voiture->appendChild($carosse);
$capot = $doc->createElement('Capot');
$carosse->appendChild($capot);
$capot->appendChild($doc->createTextNode('Impeccable !'));
//3. Le moteur et ses entrailles
$moteur = $doc->createElement('Moteur');
$voiture->appendChild($moteur);
$cyls = $doc->createElement('Cylindres');
$moteur->appendChild($cyls); // et c'est tout : élément vide
$allum = $doc->createElement('Allumage');
$moteur->appendChild($allum);
$allum-> appendChild($doc->createTextNode("En bon etat"));
//3. La transmission
$trans = $doc->createElement('Transmission');
$voiture->appendChild($trans);
$trans-> setAttribute('type', 'manuel');
$trans-> setAttribute('nb_vitesses', '4');
$trans->appendChild($doc->createElement("Boite")); //
fils vide
$trans->appendChild($doc->createElement('TrainAV'));
$trans->appendChild($doc->createElement('TrainAR'));
// Et voila tout !
// Sortie sur fichier
$doc->save ('Voiture2.xml');
?>
Exécution :
On note que le texte XML contenu dans le fichier ne contient aucune
indentation, il est donc illisible pour l'œil humain.
D'où l'utilité de la commande xmllint --format
!
jfp% php consVoiture.php
jfp% cat Voiture2.xml
<?xml version="1.0"?>
<Voiture marque="Citroen"
modele="AX"><Carosserie><Capot>Impeccable
!</Capot></Carosserie><Moteur><Cylindres/><Allumage>En
bon
etat</Allumage></Moteur><Transmission
type="manuel"
nb_vitesses="4"><Boite/><TrainAV/><TrainAR/></Transmission></Voiture>
jfp% xmllint --format Voiture2.xml
<?xml version="1.0"?>
<Voiture marque="Citroen" modele="AX">
<Carosserie>
<Capot>Impeccable
!</Capot>
</Carosserie>
<Moteur>
<Cylindres/>
<Allumage>En bon
etat</Allumage>
</Moteur>
<Transmission type="manuel" nb_vitesses="4">
<Boite/>
<TrainAV/>
<TrainAR/>
</Transmission>
</Voiture>
-
Le problème général pour exploiter des données fournies en texte est de
décrire comment ces données sont représentées
(ce que les informaticiens appellent la syntaxe du fichier).
L'avantage de XML sur le texte est que cette syntaxe est décrite par la
DTD !
-
- les noms et les notes sont donnés ligne par
ligne, un
non
& une note par ligne
- séparateurs entre noms et notes : blancs et
tabulations
- codage UTF-8, sauts de ligne Unix ("
\n
")
Exemple, extrait du fichier NomsNotes.txt
Paulette
09
Hélène 18
Julien 13
Josette 19
-
Syntaxe (DTD) du fichier XML (but)
Rappelons les deux structures que nous avons définies précédemment.
-
Exemple :
?xml version="1.0" encoding="UTF-8"?>
<liste>
<eleve nom="
Paulette
"
note="09"/>
<eleve
nom="Hélène" note="18"/>
<eleve nom="Julien" note="13"/>
<eleve nom="
Josette
"
note="19"/>
</liste>
DTD :
<?xml version="1.0"?>
<!-- Tableau Noms-Notes par attributs -->
<!ELEMENT liste (eleve*)>
<!ELEMENT eleve EMPTY>
<!ATTLIST eleve nom CDATA #REQUIRED>
<!ATTLIST eleve note CDATA #REQUIRED>
-
Exemple :
<?xml version="1.0"?>
<liste>
<eleve>
<nom>Paulette</nom>
<note>09</note>
</eleve>
<eleve>
<nom>Hélène</nom>
<note>18</note>
</eleve>
<eleve>
<nom>Julien</nom>
<note>13</note>
</eleve>
<eleve>
<nom>Josette</nom>
<note>19</note>
</eleve>
</liste>
DTD
<?xml version="1.0" ?>
<!-- Tableau Noms-Notes par enfants -->
<!ELEMENT liste (eleve*)>
<!ELEMENT eleve (nom, note)>
<!ELEMENT nom (#PCDATA)>
<!ELEMENT note (#PCDATA)>
-
fichier
NN1-FromText.php
<?php
function doc1fromText($nomFich){ // construit le DOMDocument
$doc = new DOMDocument();
$rac = $doc->createElement("liste");
$doc->appendChild($rac);
$lignes = file($nomFich);
foreach( $lignes as $ligne ){
// lire le nom et la note
$nom_note = split("[ \t]+", $ligne);
$le_nom = $nom_note[0];
$la_note = rtrim($nom_note[1]);
// créer et mettre en place le DOMElement "eleve" correspondant
$elv = $doc->createElement("eleve");
$rac->appendChild($elv);
$elv->setAttribute("nom", $le_nom);
$elv->setAttribute("note", $la_note);
}
return $doc;
}// doc1fromText
// Exécution
$doc = doc1fromText("Ex1.txt");
$doc->save("Ex1.1.xml");
?>
-
fichier
NN2-FromText.php
Le programme est exactement le même, sauf pour la phase de construction de l'élément "eleve"
.
Les deux lignes
$elv->setAttribute("nom", $le_nom);
$elv->setAttribute("note", $la_note);
sont remplacées par
$elt_nom = $doc->createElement("nom");
$elv->appendChild($elt_nom);
$elt_nom->appendChild($doc->createTextNode($nom));
$elt_note = $doc->createElement("note");
$elv->appendChild($elt_note);
$elt_note->appendChild($doc->createTextNode($note));
Variation : modifier un DOMDocument
illustrée par l'exemple : ajouter ou modifier une note.
Cette opération combine la lecture du DOMDocument et la création d'éléments que nous venons de voir.
En voici une réalisation pour la représentation 1 (par attributs)
fichier DonnNote.php
<?php
function donnerNote($doc, $nom_donne, $note_donnee){
$leseleves = $doc->getElementsByTagName('eleve');
foreach( $leseleves as $leleve ){
if( $leleve->getAttribute('nom') == $nom_donne ){
$leleve->setAttribute('note', $note_donnee);
return $doc;
}
}
// et si on n'a pas trouvé le nom, on ajoute un élève
$elv = $doc->createElement('eleve');
$doc->lastChild->appendChild($elv);
$elv->setAttribute('nom', $nom_donne);
$elv->setAttribute('note', $note_donnee);
return $doc;
}//donnerNote
$doc = new DOMDocument();
$doc->load('Ex1.xml');
donnerNote($doc, 'Pierre', 14);
donnerNote($doc, 'Jules', 14);
$doc->save('Ex1b.xml');
?>