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