Réponses:
De nos jours, l'option la plus populaire (et la plus simple) est l' API ElementTree , qui est incluse dans la bibliothèque standard depuis Python 2.5.
Les options disponibles pour cela sont:
Voici un exemple de la façon de générer votre exemple de document à l'aide du cElementTree in-stdlib:
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 cela fonctionne, mais je suppose que les espaces blancs ne sont pas significatifs. Si vous avez besoin d'une indentation "prettyprint", faites-le moi savoir et je chercherai comment faire cela. (Cela peut être une option spécifique à LXML. Je n'utilise pas beaucoup l'implémentation stdlib)
Pour plus d'informations, voici quelques liens utiles:
En guise de note finale, cElementTree ou LXML devrait être suffisamment rapide pour tous vos besoins (les deux sont du code C optimisé), mais si vous vous trouvez dans une situation où vous avez besoin de tirer le maximum de performances, les repères sur le site LXML indique que:
xml_declaration=True
si vous spécifiez un encodage ... mais, pour obtenir un comportement équivalent, appelez tree.write()
comme ceci: tree.write("filename.xml", xml_declaration=True, encoding='utf-8')
Vous pouvez utiliser n'importe quel encodage tant que vous spécifiez explicitement une. ( ascii
forcera tous les caractères Unicode en dehors de l'ensemble ASCII 7 bits à être encodés par entité si vous ne faites pas confiance à un serveur Web pour être configuré correctement.)
vlaue2
à value2
: La faute de frappe est la sortie XML demandé dans la question initiale. Jusqu'à ce que cela change, la faute de frappe ici est en fait correcte.
cElementTree
été déprécié en Python 3.3
La bibliothèque lxml comprend une syntaxe très pratique pour la génération XML, appelée E-factory . Voici comment je donnerais 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)
Production:
<root>
<doc>
<field1 name="blah">some value1</field1>
<field2 name="asdfasd">some value2</field2>
</doc>
</root>
Il prend également en charge l'ajout à un nœud déjà fait, par exemple après ce qui précède, vous pourriez dire
the_doc.append(FIELD2('another value again', name='hithere'))
getattr
, par exemple, getattr(E, "some-tag")
.
Yattag http://www.yattag.org/ ou https://github.com/leforestier/yattag fournit une API intéressante pour créer un tel document XML (et aussi des documents HTML).
Il utilise le gestionnaire de contexte et le with
mot - clé.
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)
vous obtiendrez donc:
<root>
<doc>
<field1 name="blah">some value1</field1>
<field2 name="asdfasd">some value2</field2>
</doc>
</root>
Pour le choix le plus simple, j'irais avec minidom: http://docs.python.org/library/xml.dom.minidom.html . Il est intégré à la bibliothèque standard python et est simple à utiliser dans des cas simples.
Voici un tutoriel assez facile à suivre: http://www.boddie.org.uk/python/XML_intro.html
Pour une structure XML aussi simple, vous ne voudrez peut-être pas impliquer un module XML complet. Considérez 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 la boucle sur une liste de données pour produire le xml interne de votre liste de documents. C'est un peu plus délicat avec les modèles de chaîne python bruts
Pour un exemple de Jinja, voir ma réponse à une question similaire .
Voici un exemple de génération de votre xml avec des modèles de chaînes.
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
Production:
<root>
<doc>
<field1 name="foo">The value for the foo document</field1>
<field2 name="bar">The <value> for the <bar> document</field2>
</doc>
</root>
Le point négatif de l'approche du modèle est que vous ne serez pas échapper de <
et >
gratuitement. J'ai dansé autour de ce problème en tirant un utilitaire dexml.sax
Je viens de finir d'écrire un générateur xml, en utilisant la méthode des modèles de bigh_29 ... c'est une bonne façon de contrôler ce que vous produisez sans que trop d'objets soient «gênants».
En ce qui concerne la balise et la valeur, j'ai utilisé deux tableaux, l'un qui donnait le nom et la position de la balise dans le xml de sortie et un autre qui faisait référence à un fichier de paramètres ayant la même liste de balises. Le fichier de paramètres, cependant, a également le numéro de position dans le fichier d'entrée (csv) correspondant d'où les données seront extraites. De cette façon, s'il y a des changements dans la position des données provenant du fichier d'entrée, le programme ne change pas; il calcule dynamiquement la position du champ de données à partir de la balise appropriée dans le fichier de paramètres.