M1 XML 3.pptx

Transcription

M1 XML 3.pptx
Cours XML de Master1 (3/3) - J. Lehuen - Université du Maine
1
et son environnement
PARTIE 3/3
Application Programming Interfaces pour XML
➛ API DOM (Document Object Model)
➛ API SAX (Simple API for XML)
© Jérôme Lehuen - version du 02/10/13
Cours XML de Master1 (3/3) - J. Lehuen - Université du Maine
2
Deux API pour XML
• API de type évènementielle et séquentielle :
– Parcours séquentiel de l’arbre XML (génère un flux d’événement)
– Adapté à l'échange de données et aux fichiers de configuration
API SAX
... evt3 . evt2 . evt1
Application
• API de type objet et hiérarchique :
– Instanciation d’un arbre représentant le document dans sa totalité
– Adapté à la manipulation de documents chargés en mémoire
DOCUMENT_NODE
PI_NODE
COMMENT_NODE
ELEMENT_NODE (rapport)
API DOM
Application
ELEMENT_NODE (titre)
ELEMENT_NODE (texte)
TEXT_NODE
TEXT_NODE
Cours XML de Master1 (3/3) - J. Lehuen - Université du Maine
Partie 1 : Document Object Model
3
• DOM est une API standard issue d’une recommandation du W3C :
– Disponible pour tous les langages objets (C++, Java, PHP, Ruby, etc.)
– Les méthodes et procédures de manipulation DOM sont exactement les
mêmes, quelque soit la plateforme et le langage
– DOM se divise en deux spécifications :
• La spécification DOM level 1 se sépare en deux catégories :
– Core DOM level 1 = spécification générale pour tous les documents XML
– HTML DOM level 1 = spécification retenant les méthodes applicables à HTML
• La spécification DOM level 2 ajoute de nouvelles fonctionnalités :
– Prise en compte des feuilles de style CSS
• DOM représente l’arbre XML sous la forme d’objets et de relations :
– Aussi bien le document que chaque nœud devient un objet à part
entière avec sa définition, ses propriétés et ses méthodes
– Permet de conserver en mémoire et de manipuler des documents XML
– Javascript utilise DOM pour naviguer au sein du document HTML
Cours XML de Master1 (3/3) - J. Lehuen - Université du Maine
Relations dans un DOM (1)
4
Cours XML de Master1 (3/3) - J. Lehuen - Université du Maine
5
Relations dans un DOM (2)
• Permettent de naviguer de proche en proche dans un arbre :
ParentNode
Parent
Child
FirstChild
NextSiblings
PreviousSiblings
Siblings
LastChild
Cours XML de Master1 (3/3) - J. Lehuen - Université du Maine
6
Les classes du DOM
• Les principales classes DOM en PHP sont :
– – – – – objet
objet
objet
objet
objet
nœud : DomNode (superclasse de tous les objets DOM)
document : DomDocument (point d’entrée du document XML)
élément : DomElement (élément correspondant à une balise)
attribut : DomAttr (attribut attaché à un élément)
liste de nœuds : DomNodeList (liste de DomNode)
Node
Document
DocumentType
DocumentFragment
Entity
EntityReference
CharacterData
Attr
Comment
Notation
Element
ProcessingInstruction
Text
CDATASection
Cours XML de Master1 (3/3) - J. Lehuen - Université du Maine
L’objet document (1)
7
• L’objet document représente l’arbre XML entier :
– Pour créer un document, il suffit d’instancier la classe DomDocument
– Pour charger des données à partir d’un fichier, il y a la méthode load()
– Il est possible de valider le document par rapport à une DTD :
$dom = new DomDocument();
$dom->load("fichier.xml");
if ($dom->validate()) {...}
– On peut aussi charger des données à partir d’une chaîne de caractères :
$xml = "<livre><titre>PHP 5 avancé</titre></livre>";
$dom = new DomDocument();
$dom->loadXML($xml);
– Il est également possible de charger une page HTML :
$dom->loadHtmlFile("http://www.php.net");
Cours XML de Master1 (3/3) - J. Lehuen - Université du Maine
L’objet document (2)
8
– Pour sauvegarder un document, il y a la méthode save() :
$dom = new DomDocument();
...
$dom->save("nouveauFichier.xml");
– Il est également possible de le sérialiser dans une chaîne de caractères :
$dom = new DomDocument();
...
$chaine = $dom->saveXML();
– Pour obtenir une belle sortie indentée, il faut configurer le document :
$dom = new DomDocument();
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$dom->load("fichier.xml");
...
$dom->save("nouveauFichier.xml");
Cours XML de Master1 (3/3) - J. Lehuen - Université du Maine
9
L’objet document (3)
– La racine du document est accessible via l’attribut documentElement :
$dom = new DomDocument();
$dom->load("fichier.xml");
$root = $dom->documentElement;
– On peut retrouver le nœud document depuis n’importe quel nœud :
$node = ...
$dom = $node->ownerDocument;
Cours XML de Master1 (3/3) - J. Lehuen - Université du Maine
10
Propriétés d’un nœud (1)
• Type d’un nœud :
– Lorsqu’on parcours un DOM, on ne sait pas à l’avance sur quel type de
nœud on va tomber => on peut être amené à vérifier son type
– On retrouve le type d’un nœud à partir de son attribut nodeType :
$type = $node->nodeType;
Entier
retourné
Type de nœud
Constante associée
1
Élément
XML_ELEMENT_NODE
2
Attribut
XML_ATTRIBUTE_NODE
3
Texte
XML_TEXT_NODE
4
Section CDATA
XML_CDATA_SECTION_NODE
5
Entité externe
XML_ENTITY_REF_NODE
6
Entité
XML_ENTITY_NODE
7
Processing instruction
XML_PI_NODE
8
Commentaire
XML_COMMENT_NODE
9
Document
XML_DOCUMENT_NODE
Cours XML de Master1 (3/3) - J. Lehuen - Université du Maine
11
Propriétés d’un nœud (2)
• On retrouve également le nom et la valeur d’un nœud via les
attributs nodeName et nodeValue :
– Attention : les nœuds de type « élément » n’ont pas de valeur en soit
(ce sont éventuellement leurs fils de type « texte » qui en ont) mais ils
possèdent quand même un attribut nodeValue :
$xml = "<livre>Alice</livre>";
$dom= new DomDocument();
$dom->loadXML($xml);
$root = $dom->documentElement;
echo $root->nodeType;
echo $root->nodeName;
echo $root->nodeValue;
echo $root->firstChild->nodeType;
echo $root->firstChild->nodeName;
echo $root->firstChild->nodeValue;
>
>
>
>
>
>
1
livre
Alice
3
#text
Alice
Cours XML de Master1 (3/3) - J. Lehuen - Université du Maine
Navigation dans un DOM (1)
• Les listes de nœuds (DomNodeList) :
– Elles peuvent contenir tout type de nœuds (éléments, attributs, etc.)
• Liste des nœuds fils d’un élément : $node->childNodes
• Liste des attributs d’un élément : $node->attributes
– On peut les parcourir : foreach($nodeList as $node) {...}
– On peut accéder à un item particulier : $nodeList->item(0)
– On peut connaître leur taille : $nodeList->length
– Exercice : Que retourne le code PHP suivant ?
$xml = "<A>A<C>B<E/></C><D>C</D>D</A>";
$dom= new DomDocument();
$dom->loadXML($xml);
$root = $dom->documentElement;
foreach ($root->childNodes as $node) {
echo $node->nodeValue;
}
12
Cours XML de Master1 (3/3) - J. Lehuen - Université du Maine
13
Navigation dans un DOM (2)
• Attributs et méthodes d’accès aux « proches » d’un élément :
– – – – – – – – – Accéder au nœud père :$node->parentNode
Savoir si un nœud a des fils : $node->hasChildNodes()
Accéder au premier fils : $node->firstChild
Accéder au dernier fils : $node->lastChild
Obtenir la liste des fils : $node->childNodes
Accéder au deuxième fils : $node->childNodes->item(1)
Accéder au frère précédent :$node->previousSibling
Accéder au frère suivant :$node->nextSibling
Obtenir la liste des frères : $node->parentNode->childNodes
• Recherche de nœuds dans tout le document :
$nodeList = $dom->getElementsByTagName("name");
foreach ($nodeList as $node) {...}
Cours XML de Master1 (3/3) - J. Lehuen - Université du Maine
14
Navigation dans un DOM (3)
• Attributs et méthodes d’accès aux attributs d’un élément :
– – – – – Savoir si un nœud a un attribut : $node->hasAttribute("id")
Accéder à un attribut particulier : $node->getAttributeNode("id")
Obtenir directement sa valeur : $node->getAttribute("id")
Savoir si un nœud a des attributs : $node->hasAttributes()
Obtenir la liste des attributs : $node->attributes
$xml = "<livre type='conte'>Alice</livre>";
$dom = new DomDocument();
$dom->loadXML($xml);
$root = $dom->documentElement;
$node = $root->getAttributeNode("type");
echo $node->nodeType;
echo $node->nodeName;
echo $node->nodeValue;
> 2
> type
> conte
Cours XML de Master1 (3/3) - J. Lehuen - Université du Maine
Navigation dans un DOM (4)
15
• Squelette d’une fonction de traitement récursif d’un nœud :
function handleNode(DomNode $node) {
switch ($node->nodeType) {
case XML_DOCUMENT_NODE:
handleNode($node->documentElement);
break;
case XML_ELEMENT_NODE:
$name = $node->nodeName;
...
foreach ($node->attributes as $attr) handleNode($attr);
foreach ($node->childNodes as $child) handleNode($child);
break;
case XML_ATTRIBUTE_NODE:
$name = $node->nodeName;
$value = $node->nodeValue;
...
break;
case XML_TEXT_NODE:
$text = $node->nodeValue;
...
break;
Cours XML de Master1 (3/3) - J. Lehuen - Université du Maine
Modification d’un DOM (1)
• Créer un document et y accrocher une racine :
$dom = new DomDocument();
$root = $dom->createElement("livres");
$dom->appendChild($root);
• Créer un élément et y accrocher un nœud textuel :
$titre = $dom->createElement("titre");
$texte = $dom->createTextNode("Harry Potter");
$titre->appendChild($texte);
• Créer un élément et y ajouter deux attributs :
$livre = $dom->createElement("livre");
$livre->setAttribute("isbn", "2070541274");
$livre->setAttribute("pages", "232");
16
Cours XML de Master1 (3/3) - J. Lehuen - Université du Maine
Modification d’un DOM (2)
17
• Cloner un élément existant :
$clone = $node->cloneNode();
$clone = $node->cloneNode(true);
– La seconde version clone également tout le sous-arbre de l’élément
• Supprimer un élément fils par sa référence :
$node->removeChild($child);
– Tous les descendants du nœud supprimé le seront également
• Supprimer un attribut par son nom :
$node->removeAttribute("nom");
Cours XML de Master1 (3/3) - J. Lehuen - Université du Maine
Facilités XPath et XSLT en PHP
• Effectuer une requête XPath :
$dom = new DomDocument();
$dom->load("cars.xml");
$xpath = new DomXpath($dom);
$query = "//car[@make='BMW']";
$nodeList = $xpath->query($query);
• Effectuer une transformation XSLT :
$source = new DomDocument();
$source->load("cars.xml");
$style = new domDocument();
$style->load("transformation.xsl");
$moteur = new XSLTProcessor();
$moteur->importStylesheet($style);
$moteur->setParameter("", "par1", "val1");
$moteur->setParameter("", "par2", "val2");
$resultat = $moteur->transformToXml($source);
18
Cours XML de Master1 (3/3) - J. Lehuen - Université du Maine
19
Partie 2 : Simple API for XML
• Pourquoi une autre API pour XML ?
– Les applications qui utilisent DOM souffrent du fait que cette API impose
de construire un arbre en mémoire contenant l’intégralité des éléments
du document => pose problème pour les très gros documents.
– SAX, quand à lui, ne construit rien en mémoire : il se contente de
parcourir le document et de générer des événements qui seront pris en
compte par l’application (ou pas).
• SAX est basé sur un modèle événementiel :
– SAX repose d’une part sur la génération systématique d’évènements
(envois de messages) et d’autre part sur leur prise en compte.
– Une application utilisant SAX implémente un gestionnaire de contenu lui
permettant d’effectuer des opérations adaptées, en fonction du type du
nœud rencontré à un moment donné.
Cours XML de Master1 (3/3) - J. Lehuen - Université du Maine
20
Quelques évènements SAX
• Qu’est-ce qu’un API évènementielle ?
Parseur SAX
Application
parse ( « cars.xml » )
startDocument ()
startElement ( « cars », null )
startElement ( « car », attributs )
startElement ( « model », null )
<cars>
<car make="BMW">
<model>Z4 Roadster</model>
<year>2012</year>
...
</car>
...
</cars>
characters ( « Z4 Roadster » )
endElement ( « model » )
startElement ( « year », null )
Cours XML de Master1 (3/3) - J. Lehuen - Université du Maine
Mise en œuvre de SAX en Java (1)
21
• Mise en œuvre d’un org.xml.sax.XMLReader (validant) :
import org.xml.sax.*;
import org.xml.sax.helpers.*;
import java.io.IOException;
public class SAXParser {
public SAXParser(String fileName) {
try {
XMLReader reader = XMLReaderFactory.createXMLReader();
reader.setFeature("http://xml.org/sax/features/validation", true);
reader.parse(fileName);
}
catch (SAXException e) { System.err.println(e); }
catch (IOException e) { System.err.println(e); }
}
public static void main(String[] args) {
new SAXParser(args[0]);
}
}
– Il ne se passe rien… (normal, il n’y a pas de gestionnaire de contenu)
Cours XML de Master1 (3/3) - J. Lehuen - Université du Maine
Mise en œuvre de SAX en Java (2)
• Ajout d’un org.xml.sax.ContentHandler :
public class SAXParser extends DefaultHandler {
public SAXParser(String fileName) {
try {
XMLReader reader = XMLReaderFactory.createXMLReader();
reader.setFeature("http://xml.org/sax/features/validation", true);
reader.setContentHandler(this);
reader.parse(fileName);
}
catch (SAXException e) { System.err.println(e); }
catch (IOException e) { System.err.println(e); }
}
public
public
public
public
public
void
void
void
void
void
startDocument() {}
endDocument() {}
startElement(String uri, String name, String raw, Attributes attrs) {}
endElement(String uri, String name, String raw) {}
characters(char buf[], int offset, int length) {}
}
– Il ne se passe toujours rien… (normal, les méthodes sont vides)
22
Cours XML de Master1 (3/3) - J. Lehuen - Université du Maine
Mise en œuvre de SAX en Java (3)
23
• Surcharge de quelques méthodes de l’interface ContentHandler :
public void startElement(String uri, String localName, String name, Attributes att) {
System.out.println("** Début de l’élément: " + localName);
for (int i = 0 ; i < att.getLength() ; i++)
System.out.println("** Attribut: " + att.getLocalName(i) + "=" + att.getValue(i));
}
public void endElement(String uri, String localName, String name) {
System.out.println("** Fin de l’élément: " + localName);
}
public void characters(char buf[], int offset, int length) {
System.out.println("** Texte: " + new String(buf, offset, length));
}
** Début du document
** Début de l’élément: cars
** Début de l’élément: car
** Attribut: make=BMW
** Début de l’élément: model
** Texte: Z4 Roadster
** Fin de l’élément: model
** Début de l'élément: year
** Texte: 2012
** Fin de l’élément: year
** Début de l’élément: price
** Attribut: currency=Euros
** Texte: 47500
** Fin de l’élément: price
** Début de l’élément: country
** Texte: Germany
** Fin de l’élément: country
** Fin de l’élément: car
** Début de l’élément: car
** Attribut: make=Peugeot
** Début de l’élément: model
** Texte: 308 SW Style
** Fin de l’élément: model
** Début de l’élément: year
** Texte: 2012
** Fin de l’élément: year
** Début de l’élément: price
** Attribut: currency=Euros
** Texte: 17790
** Fin de l’élément: price
** Fin de l’élément: car
** Début de l’élément: car
** Attribut: make=Peugeot
** Début de l’élément: model
** Texte: RCZ Coup?
** Fin de l’élément: model
** Début de l’élément: year
** Texte: 2013
** Fin de l’élément: year
** Début de l’élément: price
** Attribut: currency=Euros
** Texte: 29900
** Fin de l’élément: price
** Fin de l’élément: car
** Fin de l’élément: cars
** Fin du document
Cours XML de Master1 (3/3) - J. Lehuen - Université du Maine
Gestionnaires SAX (1)
• Qu’est-ce qu’un gestionnaire ?
– Un gestionnaire est un ensemble de « callbacks » que SAX définit pour
pouvoir faire correspondre du code applicatif à des évènements
– SAX 2.0 définit quatre gestionnaires (dans org.xml.sax) :
• ContentHandler, ErrorHandler, DTDHandler, EntityResolver
– Des gestionnaires peuvent être enregistrés auprès du parseur :
• setContentHandler, setErrorHandler, setDTDHandler, setEntityResolver
• La classe utilitaire DefaultHandler :
– Propose une implémentation par défaut des quatre gestionnaires SAX
• http://www.saxproject.org/apidoc/org/xml/sax/helpers/DefaultHandler.html
– Il suffit de spécialiser la classe DefaultHandler et surcharger les
méthodes qui nous intéressent
24
Cours XML de Master1 (3/3) - J. Lehuen - Université du Maine
Gestionnaires SAX (2)
25
• Méthodes de l’interface ContentHandler :
Cours XML de Master1 (3/3) - J. Lehuen - Université du Maine
Gestionnaires SAX (3)
• Méthodes de l’interface ErrorHandler :
• Exemple de surcharge de la méthode « error » de DefaultHandler :
public void error(SAXParseException e) throws SAXException
{
System.out.println("** Error **");
System.out.println("
Ligne
: " + e.getLineNumber());
System.out.println("
Message : " + e.getMessage());
throw new SAXException("Document non valide");
}
– Il peut être intéressant de faire remonter les exceptions, par exemple
vers une interface graphique qui fera apparaître une fenêtre…
26