Membuat file XML sederhana menggunakan python

161

Apa pilihan saya jika saya ingin membuat file XML sederhana dengan python? (bijaksana perpustakaan)

Xml yang saya inginkan terlihat seperti:

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

</root>
Blankman
sumber

Jawaban:

310

Saat ini, opsi paling populer (dan sangat sederhana) adalah ElementTree API , yang telah dimasukkan dalam pustaka standar sejak Python 2.5.

Opsi yang tersedia untuk itu adalah:

  • ElementTree (Dasar, implementasi Python murni dari ElementTree. Bagian dari pustaka standar sejak 2.5)
  • cElementTree (Dioptimalkan implementasi C dari ElementTree. Juga ditawarkan di perpustakaan standar sejak 2.5)
  • LXML (Berdasarkan libxml2. Menawarkan superset yang kaya dari ElementTree API serta XPath, Pemilih CSS, dan banyak lagi)

Berikut ini adalah contoh cara membuat dokumen contoh menggunakan 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")

Saya sudah mengujinya dan berfungsi, tapi saya berasumsi spasi tidak signifikan. Jika Anda membutuhkan lekukan "cetak awal", beri tahu saya dan saya akan mencari cara melakukannya. (Ini mungkin opsi khusus LXML. Saya tidak terlalu banyak menggunakan stdlib implementasi)

Untuk bacaan lebih lanjut, berikut adalah beberapa tautan bermanfaat:

Sebagai catatan terakhir, baik cElementTree atau LXML harus cukup cepat untuk semua kebutuhan Anda (keduanya adalah kode C yang dioptimalkan), tetapi jika Anda berada dalam situasi di mana Anda perlu memeras setiap bit kinerja terakhir, tolok ukur pada situs LXML menunjukkan bahwa:

  • LXML jelas menang untuk serialisasi (menghasilkan) XML
  • Sebagai efek samping dari penerapan induk traversal yang tepat, LXML sedikit lebih lambat dari cElementTree untuk penguraian.
ssokolow
sumber
1
@ Kakas: Saya tidak punya Mac jadi saya tidak bisa mencoba menduplikasi masalah. Katakan versi Python dan saya akan melihat apakah saya dapat mereplikasi di Linux.
ssokolow
4
@nonsensickle Anda seharusnya mengajukan pertanyaan baru dan kemudian mengirim saya tautan ke sana sehingga semua orang dapat memperoleh manfaat darinya. Namun, saya akan mengarahkan Anda ke arah yang benar. Pustaka DOM (Document Object Model) selalu membangun model dalam-memori sehingga Anda menginginkan implementasi SAX (Simple API for XML). Saya belum pernah melihat implementasi SAX tapi ini tutorial untuk menggunakan in-stdlib untuk output daripada input.
ssokolow
1
@YonatanSimson Saya tidak tahu cara menambahkan string yang tepat , karena ElementTree tampaknya hanya mematuhi xml_declaration=Truejika Anda menentukan pengkodean ... tetapi, untuk mendapatkan perilaku yang setara, panggil tree.write()seperti ini: tree.write("filename.xml", xml_declaration=True, encoding='utf-8')Anda dapat menggunakan pengkodean apa saja selama Anda secara eksplisit menentukan satu. ( asciiakan memaksa semua karakter Unicode di luar ASCII 7-bit yang ditetapkan untuk dikodekan entitas jika Anda tidak mempercayai server web untuk dikonfigurasikan dengan benar.)
ssokolow
1
Hanya pengingat kepada orang lain yang mencoba untuk memperbaiki vlaue2ke value2: ketik adalah output XML yang diminta di pertanyaan awal. Sampai itu berubah, kesalahan ketik di sini sebenarnya sudah benar.
ssokolow
3
Menurut dokumentasi , cElementTreedisusutkan dalam Python 3.3
Stevoisiak
63

The perpustakaan lxml termasuk sintaks yang sangat nyaman untuk generasi XML, yang disebut E-pabrik . Inilah cara saya membuat contoh yang Anda berikan:

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

Keluaran:

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

Ini juga mendukung penambahan ke simpul yang sudah dibuat, misalnya setelah di atas Anda bisa mengatakan

the_doc.append(FIELD2('another value again', name='hithere'))
rescdsk
sumber
3
Jika nama tag tidak sesuai dengan aturan pengidentifikasi Python, maka Anda dapat menggunakan getattr, misalnya getattr(E, "some-tag"),.
haridsv
bagi saya cetak lxml.etree.tostring menyebabkan AttributeError: 'lxml.etree._Element' objek tidak memiliki atribut 'etree'. Ini bekerja tanpa memulai "lxml." like: etree.tostring (the_doc, pretty_print = True)
kodlan
19

Yattag http://www.yattag.org/ atau https://github.com/leforestier/yattag menyediakan API yang menarik untuk membuat dokumen XML tersebut (dan juga dokumen HTML).

Itu menggunakan manajer konteks dan withkata kunci.

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)

jadi Anda akan mendapatkan:

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

Untuk struktur XML sederhana seperti itu, Anda mungkin tidak ingin melibatkan modul XML penuh sesak nafas. Pertimbangkan templat string untuk struktur paling sederhana, atau Jinja untuk sesuatu yang sedikit lebih kompleks. Jinja dapat menangani perulangan pada daftar data untuk menghasilkan xml bagian dalam daftar dokumen Anda. Itu agak rumit dengan template string python mentah

Untuk contoh Jinja, lihat jawaban saya untuk pertanyaan serupa .

Berikut ini contoh membuat xml Anda dengan templat string.

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

Keluaran:

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

Kelemahan dari pendekatan template adalah bahwa Anda tidak akan lolos <dan >gratis. Saya menari di sekitar masalah itu dengan menarik util darixml.sax

bigh_29
sumber
1

Saya baru saja selesai menulis generator xml, menggunakan metode Templat bigh_29 ... ini adalah cara yang bagus untuk mengontrol apa yang Anda hasilkan tanpa terlalu banyak Objek yang mendapatkan 'penghalang'.

Adapun tag dan nilai, saya menggunakan dua array, satu yang memberi nama tag dan posisi di output xml dan yang lain yang mereferensikan file parameter yang memiliki daftar tag yang sama. File parameter, bagaimanapun, juga memiliki nomor posisi dalam file input (csv) yang sesuai di mana data akan diambil. Dengan cara ini, jika ada perubahan pada posisi data yang masuk dari file input, program tidak berubah; itu secara dinamis bekerja posisi bidang data dari tag yang sesuai dalam file parameter.

Cloughie
sumber