2010-08-31 12 views
95

Quali sono le mie opzioni se voglio creare un semplice file XML in python? (Biblioteca saggio)Creazione di un semplice file XML usando python

Il xml che voglio assomiglia:

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

</root> 

risposta

190

In questi giorni, l'opzione più popolare (e molto semplice) è il ElementTree API, che è stato incluso nella libreria standard dal Python 2.5.

Le opzioni disponibili per questo sono:

  • elementtree (di base, implementazione puro Python di ElementTree parte della libreria standard dal 2.5.)
  • cElementTree (implementazione C ottimizzata delle ElementTree offerti anche in. la libreria standard dal 2,5)
  • LXML (Basato su libxml2. offre una ricca superset delle API ElementTree pure XPath, CSS selettori, e altro ancora)

Ecco un esempio di come generare il documento di esempio utilizzando il 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") 

ho provato e funziona, ma sto assumendo la spaziatura non è significativo. Se hai bisogno di indentazione "prettyprint", fammi sapere e cercherò come farlo. (. Può essere un'opzione specifica per LXML Io non uso l'attuazione stdlib molto)

Per ulteriori letture, ecco alcuni link utili:

Come nota finale, sia cElementTree o LXML dovrebbe essere abbastanza veloce per tutte le esigenze (entrambi sono ottimizzati codice C), ma nel caso in cui si trovi in ​​una situazione in cui è necessario spremere fino all'ultimo bit di prestazioni, i parametri di riferimento sul sito LXML indicano che:

  • LXML vince nettamente per la serializzazione (generazione) XML
  • Come un lato- effetto di implementare l'attraversamento genitore appropriato, LXML è un po 'più lento di cElementTree per l'analisi.
+0

Ricevo 'import xml.etree.cElementTree come ET', 'ImportError: nessun modulo chiamato etree.cElementTree' - python standard OSX 10.8, ma funziona in qualche modo quando lo eseguo dall'interno di ipython. – guaka

+1

@Kasper: Non ho un Mac, quindi non posso provare a duplicare il problema. Dimmi la versione di Python e vedrò se riesco a replicarla su Linux. – ssokolow

+0

@ssokolow, ora sono su OSX 10.9 e questo è stato in qualche modo risolto, non ricordo se fosse la mia stessa azione o se avessi fatto qualcosa per risolverlo. – guaka

46

lxml library include una sintassi molto comoda per la generazione XML, denominata E-factory.Ecco come mi piacerebbe fare l'esempio si dà:

#!/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) 

uscita:

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

Esso supporta anche l'aggiunta di un nodo già fatto, ad esempio, dopo il sopra di voi potrebbe dire

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

Se il nome del tag non è conforme alle regole dell'identificatore Python, quindi potresti usare 'getattr', ad es.' getattr (E, "some-tag") '. – haridsv

9

Yattag http://www.yattag.org/ o https://github.com/leforestier/yattag fornisce un'API interessante per creare tale documento XML (e anche i documenti HTML).

Si sta utilizzando la parola chiave context manager e 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) 

in modo da otterrete:

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

Per un tale semplice struttura XML, non si può decidere di coinvolgere un full modulo XML soffiato. Considera un modello di corda per le strutture più semplici, o Jinja per qualcosa di un po 'più complesso. Jinja può gestire il looping su un elenco di dati per produrre l'xml interno del tuo elenco di documenti. Questo è un po 'più complicato con modelli di stringhe di pitone grezzi

Per un esempio di Jinja, vedere il mio answer to a similar question.

Ecco un esempio di generazione del tuo xml con modelli di stringhe.

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 

uscita:

<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> 

Il lato negativo dell'approccio modello è che non sarà possibile ottenere la fuga di < e > gratuitamente. Ho ballato intorno a questo problema inserendo un util da xml.sax

Problemi correlati