Risposte:
In questi giorni, l'opzione più popolare (e molto semplice) è l' API ElementTree , che è stata inclusa nella libreria standard da Python 2.5.
Le opzioni disponibili per questo sono:
Ecco un esempio di come generare il tuo documento di esempio usando in-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")
L'ho provato e funziona, ma presumo che lo spazio bianco non sia significativo. Se hai bisogno del rientro "prettyprint", fammelo sapere e cercherò come farlo. (Potrebbe essere un'opzione specifica per LXML. Non uso molto l'implementazione di stdlib)
Per ulteriori letture, ecco alcuni link utili:
Come nota finale, o cElementTree o LXML dovrebbero essere abbastanza veloci per tutte le tue esigenze (entrambi sono codice C ottimizzato), ma nel caso in cui ti trovi in una situazione in cui devi spremere fino all'ultimo bit di performance, i benchmark su il sito LXML indica che:
xml_declaration=True
se specifichi una codifica ... ma, per ottenere un comportamento equivalente, chiama tree.write()
così: tree.write("filename.xml", xml_declaration=True, encoding='utf-8')
Puoi usare qualsiasi codifica purché tu specifichi esplicitamente uno. ( ascii
imporrà che tutti i caratteri Unicode al di fuori del set ASCII a 7 bit siano codificati da entità se non ti fidi che un server Web sia configurato correttamente.)
vlaue2
a value2
: L'errore di battitura è l'output XML richiesto nella domanda iniziale. Fino a quando non cambia, l'errore di battitura qui è effettivamente corretto.
cElementTree
stato deprezzato in Python 3.3
La libreria lxml include una sintassi molto conveniente per la generazione XML, chiamata E-factory . Ecco come farei l'esempio che dai:
#!/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)
Produzione:
<root>
<doc>
<field1 name="blah">some value1</field1>
<field2 name="asdfasd">some value2</field2>
</doc>
</root>
Supporta anche l'aggiunta a un nodo già creato, ad esempio dopo ciò che potresti dire
the_doc.append(FIELD2('another value again', name='hithere'))
getattr
, ad es getattr(E, "some-tag")
.
Yattag http://www.yattag.org/ o https://github.com/leforestier/yattag fornisce un'API interessante per creare tale documento XML (e anche documenti HTML).
Utilizza il gestore di contesto e la with
parola chiave.
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)
così otterrai:
<root>
<doc>
<field1 name="blah">some value1</field1>
<field2 name="asdfasd">some value2</field2>
</doc>
</root>
Per la scelta più semplice, sceglierei minidom: http://docs.python.org/library/xml.dom.minidom.html . È integrato nella libreria standard di Python ed è semplice da usare in casi semplici.
Ecco un tutorial abbastanza facile da seguire: http://www.boddie.org.uk/python/XML_intro.html
Per una struttura XML così semplice, potresti non voler coinvolgere un modulo XML completo. Prendi in considerazione un modello di stringa per le strutture più semplici o Jinja per qualcosa di un po 'più complesso. Jinja può gestire il loop su un elenco di dati per produrre l'xml interno dell'elenco dei documenti. Questo è un po 'più complicato con i modelli di stringhe di pitone grezzi
Per un esempio di Jinja, vedi la mia risposta a una domanda simile .
Ecco un esempio di generazione del tuo xml con modelli di stringa.
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
Produzione:
<root>
<doc>
<field1 name="foo">The value for the foo document</field1>
<field2 name="bar">The <value> for the <bar> document</field2>
</doc>
</root>
Il lato negativo dell'approccio del modello è che non ti lascerai sfuggire <
e >
gratuitamente. Ho ballato attorno a quel problema estraendo un util daxml.sax
Ho appena finito di scrivere un generatore XML, usando il metodo dei modelli di bigh_29 ... è un bel modo di controllare ciò che emetti senza troppi oggetti che si "mettono in mezzo".
Per quanto riguarda il tag e il valore, ho usato due array, uno che indicava il nome e la posizione del tag nell'output xml e un altro che faceva riferimento a un file di parametri con lo stesso elenco di tag. Il file dei parametri, tuttavia, ha anche il numero di posizione nel file di input (csv) corrispondente da cui verranno presi i dati. In questo modo, se ci sono cambiamenti nella posizione dei dati che arrivano dal file di input, il programma non cambia; determina dinamicamente la posizione del campo dati dal tag appropriato nel file dei parametri.