python et le XML **************** extrait de http://www.grappa.univ-lille3.fr/~torre/Enseignement/Cours/XML/dom.php Introduction ============ DOM, pour Document Object Model, vise à fournir un modèle d’un document semi-structuré, autrement dit d’un document XML. Il s’agit en particulier de définir des méthodes d’accès et de modification opérant sur un tel document. DOM est défini par des recommandations du W3C, trois niveaux ont aujourd’hui été définis. Certaines parties de ces recommandations sont dédiées au traitement de documents XHTML ; nous nous concentrons ici sur le noyau de DOM fournissant des méthodes valables pour tout document XML. En pratique, DOM permet de charger un document XML tout entier en mémoire et s’oppose sur ce point à SAX (qui permet de traiter un document XML en une passe, sans occupation mémoire). Au minimum, DOM utilise une zone mémoire de la fichier XML lu ; dans les faits, c’est souvent plus et cela pour se préparer à répondre de manière efficace à des interrogations complexes. En Python, le programme minimal qui charge un document XML sous forme de DOM est le suivant : .. code-block:: python from xml.dom.minidom import parse import sys xmlfilename = sys.argv[1] dom = parse(xmlfilename) Le modèle DOM reflète la nature arborescente des documents XML : il nous permet d’accéder à la racine ou à des noeuds quelconques, d’obtenir les fils d’un noeud précis, ou encore ses frères. L’implémentation réelle du modèle présent en mémoire après le chargement du document XML est cachée dans un objet et peut varier avec le langage de programmation utilisé. Par contre les méthodes d’accès et de modification de l’arbre DOM sont standardisées par le W3C et sont donc les mêmes d’un langage à l’autre. Pour terminer, précisons que chaque information présente dans le document d’origine se retrouve en mémoire comme un noeud de l’arbre DOM : les éléments, les attributs, les textes, les commentaires, etc. sont autant de noeuds accessibles dans l’arbre DOM. Les noeuds du DOM ================= Nous venons de percevoir le rôle central des noeuds dans DOM, il convient de savoir les manipuler. Informations sur un noeud Étant donné un noeud de l’arbre DOM, nous pouvons obtenir son nom, sa valeur et son type. * nodeType 1 (élément) 2 (attribut) 3 (texte) * nodeName le nom de la balise le nom de l’attribut #text * nodeValue non définie la valeur de l’attribut le texte du noeud Obtenir un noeud ================ À partir de l’objet DOM, il est possible d’obtenir : * l’élément racine du document XML à l’aide de documentElement ; * le noeud élément portant un nom particulier à l’aide de getElementsByTagName. Si l’on possède déjà un noeud, il est alors possible d’en obtenir d’autres qui lui sont liés dans le document d’origine : * childNodes : la liste des noeuds fils ; * parentNode : le père ; * firstChild : le premier fils ; * lastChild : le dernier fils ; * nextSibling : le frère droit ; * previousSibling : le frère gauche. À noter que le noeud demandé peut ne pas exister : la racine n’a pas de père, un fils ainé n’a pas de frère gauche, etc. Dans ces cas, en Python, on obtient la valeur None. Si un noeud n’a pas de fils, childNodes renvoie logiquement une liste vide. Enfin les attributs d’un élément sont accessibles grâce à la méthode attributes (qui fournit donc un ensemble de noeuds de type 2). Premiers exemples de programmes Python & DOM ================================================ Accéder à un fils textuel --------------------------- .. code-block:: python from xml.dom.minidom import parse import sys xmlfilename = sys.argv[1] dom = parse(xmlfilename) titres = dom.getElementsByTagName("titre") premier = titres[0] texte = premier.childNodes[0] print texte.nodeValue Obtenir des attributs --------------------- .. code-block:: python from xml.dom.minidom import parse import sys xmlfilename = sys.argv[1] dom = parse(xmlfilename) sites = dom.getElementsByTagName('site') for site in sites: attrs = site.attributes urlnode = attrs['url'] print urlnode.nodeValue Lire un fichier plat -------------------- .. code-block:: python from xml.dom.minidom import parse import sys xmlfilename = sys.argv[1] dom = parse(xmlfilename) racine = dom.documentElement; fils = racine.childNodes print 'racine=',racine.nodeName for f in fils: if f.nodeType==1: print f.nodeName,'=',f.childNodes[0].nodeValue Modifier le DOM --------------- Un nouveau DOM .. code-block:: python impl = getDOMImplementation() newdoc = impl.createDocument(None,"laracine",None) top_element = newdoc.documentElement Définir un noeud ou un attribut .. code-block:: python new_element = newdoc.createElement('nomelement') new_element.setAttribute('nomattribut','valeurattribut') copie = noeud.cloneNode(True) copie.removeAttribute('nomattributasupprimer') Placer un noeud dans la structure .. code-block:: python top_element.appendChild(new_element) Produire du XML --------------- produire du XML à partir d’un noeud n : n.toxml. PrettyPrint(newdoc) Autres exemples --------------- .. code-block:: python from xml.dom.minidom import getDOMImplementation impl = getDOMImplementation() newdoc = impl.createDocument(None, "some_tag", None) top_element = newdoc.documentElement text = newdoc.createTextNode('Some textual content.') top_element.appendChild(text) dom3 = parseString("Some data") assert dom3.documentElement.tagName == "myxml" la gestion de l’encoding def gen_xml(p,title,tableid=0,formid=0): """ search info from estelle """ conn=odbc.odbc(dnsPg) cursor=conn.cursor() cursor.execute(get_content_file(p)) result = cursor.fetchall() dsc = cursor.description cursor.close() conn.close() impl = getDOMImplementation() newdoc = impl.createDocument(None,"DataList",None) top_element = newdoc.documentElement elt1 = newdoc.createElement("%sList" % title) top_element.appendChild(elt1) elt2 = newdoc.createElement("TableID") elt2.appendChild(newdoc.createTextNode(str(tableid))) elt1.appendChild(elt2) elt3 = newdoc.createElement("FormID") elt3.appendChild(newdoc.createTextNode(str(formid))) elt1.appendChild(elt3) for i in result: ct = newdoc.createElement(title) k = 0 for j in dsc: att = newdoc.createElement(str(j[0])) txt = newdoc.createTextNode(unicode(str(i[k]),'iso-8859-15')) att.appendChild(txt) ct.appendChild(att) k = k + 1 elt1.appendChild(ct) result = open('%s.xml' % title,'w') result.write(newdoc.toxml('iso-8859-15')) result.close() pass Exemple de lecture d'un fichier sur le web et de l'ouverture d'un navigateur ---------------------------------------------------------------------------- l'objectif est de simuler la navigation dans un ensemble d'url obtenu via un sitemap.xml .. code-block:: python import xml.dom.minidom import urllib2 import webbrowser import time import os BROWSER = 'iexplore.exe' TIMESLEEP = 30 def geturl(url): sitemap = xml.dom.minidom.parse(urllib2.urlopen(url)) prg = "" for loc in sitemap.getElementsByTagName('loc'): try: print("open %s" % loc.childNodes[0].nodeValue) webbrowser.open(loc.childNodes[0].nodeValue) except: print("problem with %s" % loc.childNodes[0].nodeValue) time.sleep(TIMESLEEP) os.system("taskkill /F /IM %s" % BROWSER) geturl('http://www.mascarille.com/galerie/sitemap.xml')