2010-08-31 6 views

Répondre

190

Ces jours-ci, l'option la plus populaire (et très simple) est le ElementTree API, qui a été inclus dans la bibliothèque standard depuis Python 2.5.

Les options disponibles pour ce sont:

  • ElementTree (base, la mise en œuvre pure Python de ElementTree Une partie de la bibliothèque standard depuis 2.5.)
  • cElementTree (Optimized C mise en œuvre de ElementTree également offert dans. la bibliothèque standard depuis 2.5)
  • lxml (Basé sur libxml2. offre une riche surensemble l'API elementTree ainsi XPath, CSS Selectors et plus)

Voici un exemple de la façon de générer votre document exemple en utilisant le en stdlib cElementTree:

import xml.etree.cElementTree as ET 

root = ET.Element("root") 
doc = ET.SubElement(root, "doc") 

ET.SubElement(doc, "field1", name="blah").text = "some value1" 
ET.SubElement(doc, "field2", name="asdfasd").text = "some vlaue2" 

tree = ET.ElementTree(root) 
tree.write("filename.xml") 

Je l'ai testé et il fonctionne, mais je suppose des espaces est non significatif. Si vous avez besoin de l'indentation "prettyprint", faites le moi savoir et je chercherai comment faire cela. (. Il peut être une option spécifique à LXML Je n'utilise pas la mise en œuvre de stdlib beaucoup)

Pour en savoir plus, voici quelques liens utiles:

Comme note finale, que ce soit cElementTree ou LXML devrait être assez rapide pour tous vos besoins (les deux sont optimisés code C), mais dans la si vous êtes dans une situation où vous devez faire sortir chaque bit de la performance, les points de repère sur le site LXML indiquent que:

  • LXML gagne clairement sérialisation (production) XML
  • en tant que Side- LXML est un peu plus lent que cElementTree pour l'analyse.
+0

Je reçois 'xml.etree.cElementTree d'importation comme ET',' ImportError: Aucun module nommé etree.cElementTree' - Python standard Mac OS X 10.8, mais en quelque sorte il fonctionne quand je le lance à l'intérieur ipython. – guaka

+1

@Kasper: Je n'ai pas de Mac donc je ne peux pas essayer de dupliquer le problème. Dis-moi la version Python et je verrai si je peux la répliquer sur Linux. – ssokolow

+0

@ssokolow, je suis sur OSX 10.9 maintenant et cela a en quelque sorte été résolu, je ne me souviens pas si c'était ma propre action ou si j'ai fait quelque chose pour le résoudre. – guaka

46

Le lxml library inclut une syntaxe très pratique pour la génération XML, appelée E-factory.Voici comment je ferais l'exemple que vous donnez:

#!/usr/bin/python 
import lxml.etree 
import lxml.builder  

E = lxml.builder.ElementMaker() 
ROOT = E.root 
DOC = E.doc 
FIELD1 = E.field1 
FIELD2 = E.field2 

the_doc = ROOT(
     DOC(
      FIELD1('some value1', name='blah'), 
      FIELD2('some value2', name='asdfasd'), 
      ) 
     ) 

print lxml.etree.tostring(the_doc, pretty_print=True) 

Sortie:

<root> 
    <doc> 
    <field1 name="blah">some value1</field1> 
    <field2 name="asdfasd">some value2</field2> 
    </doc> 
</root> 

Il prend également en charge l'ajout d'un nœud déjà fait, par exemple après ce qui précède, on pourrait dire

the_doc.append(FIELD2('another value again', name='hithere')) 
+1

Si le nom de la balise n'est pas conforme Aux règles d'identifiant Python, vous pouvez utiliser 'getattr', par exemple' getattr (E, "some-tag") '. – haridsv

9

Yattag http://www.yattag.org/ ou https://github.com/leforestier/yattag fournit une API intéressante pour créer un tel document XML (ainsi que les documents HTML).

Il utilise mot-clé context manager et with.

from yattag import Doc, indent 

doc, tag, text = Doc().tagtext() 

with tag('root'): 
    with tag('doc'): 
     with tag('field1', name='blah'): 
      text('some value1') 
     with tag('field2', name='asdfasd'): 
      text('some value2') 

result = indent(
    doc.getvalue(), 
    indentation = ' '*4, 
    newline = '\r\n' 
) 

print(result) 

donc vous obtiendrez:

<root> 
    <doc> 
     <field1 name="blah">some value1</field1> 
     <field2 name="asdfasd">some value2</field2> 
    </doc> 
</root> 
0

Pour une telle structure XML simple, vous voudrez peut-être pas impliquer un module XML Full Blown. Considérons un modèle de chaîne pour les structures les plus simples, ou Jinja pour quelque chose d'un peu plus complexe. Jinja peut gérer le bouclage d'une liste de données pour produire le fichier XML interne de votre liste de documents. C'est un peu plus compliqué avec des modèles de chaîne de python brut

Pour un exemple Jinja, voir mon answer to a similar question.

Voici un exemple de la génération de votre xml avec des modèles de chaîne.

import string 
from xml.sax.saxutils import escape 

inner_template = string.Template(' <field${id} name="${name}">${value}</field${id}>') 

outer_template = string.Template("""<root> 
<doc> 
${document_list} 
</doc> 
</root> 
""") 

data = [ 
    (1, 'foo', 'The value for the foo document'), 
    (2, 'bar', 'The <value> for the <bar> document'), 
] 

inner_contents = [inner_template.substitute(id=id, name=name, value=escape(value)) for (id, name, value) in data] 
result = outer_template.substitute(document_list='\n'.join(inner_contents)) 
print result 

Sortie:

<root> 
<doc> 
    <field1 name="foo">The value for the foo document</field1> 
    <field2 name="bar">The &lt;value&gt; for the &lt;bar&gt; document</field2> 
</doc> 
</root> 

Le point négatif de l'approche du modèle est que vous ne serez pas échapper à des < et > gratuitement. Je dansais autour de ce problème en tirant dans un util de xml.sax

Questions connexes