Python kullanarak basit bir XML dosyası oluşturma


162

Python'da basit bir XML dosyası oluşturmak istersem seçeneklerim nelerdir? (akıllıca kütüphane)

İstediğim xml şöyle görünüyor:

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

</root>

Yanıtlar:


311

Bu günlerde, en popüler (ve çok basit) seçenek Python 2.5'ten beri standart kütüphaneye dahil edilen ElementTree API'sıdır .

Bunun için mevcut seçenekler:

  • ElementTree (ElementTree'nin temel, saf-Python uygulaması. 2.5'ten beri standart kütüphanenin parçası)
  • cElementTree (ElementTree'nin optimize edilmiş C uygulaması. 2.5'ten beri standart kütüphanede de sunulmaktadır)
  • LXML (libxml2'ye dayanmaktadır. XPath, CSS Seçicileri ve daha fazlası ile birlikte ElementTree API'sinin zengin bir üst kümesini sunar)

Aşağıda, in-stdlib cElementTree kullanarak örnek belgenizi nasıl oluşturacağınıza ilişkin bir örnek verilmiştir:

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

Test ettim ve işe yarıyor, ama boşlukun önemli olmadığını varsayıyorum. "Prettyprint" girinti gerekiyorsa, bana bildirin, nasıl yapılacağına bakacağım. (LXML'ye özgü bir seçenek olabilir. Stdlib uygulamasını fazla kullanmıyorum)

Daha fazla okuma için, bazı yararlı bağlantılar şunlardır:

Son bir not olarak, cElementTree veya LXML tüm ihtiyaçlarınız için yeterince hızlı olmalıdır (her ikisi de optimize edilmiş C kodudur), ancak performansın her bir bitini sıkıştırmanız gereken bir durumdaysanız, LXML sitesi şunları belirtir:

  • LXML, XML serileştirme (oluşturma) için açıkça kazanıyor
  • Uygun ebeveyn geçişinin uygulanmasının bir yan etkisi olarak, LXML, ayrıştırma için cElementTree'den biraz daha yavaştır.

1
@Kasper: Mac'im yok, bu yüzden sorunu çoğaltmayı deneyemiyorum. Bana Python sürümünü söyleyin ve Linux'ta kopyalayıp kopyalayamayacağımı göreceğim.
ssokolow

4
@nonsensickle Gerçekten yeni bir soru sormalı ve sonra bana bir bağlantı göndermeliydiniz ki herkes bundan faydalanabilsin. Ancak, sizi doğru yöne yönlendireceğim. DOM (Belge Nesne Modeli) kitaplıkları her zaman bir bellek içi model oluşturur, böylece bunun yerine SAX (XML için Basit API) uygulaması istersiniz. SAX uygulamalarına hiç bakmadım, ancak burada girdi yerine stdlib olanı çıktı için kullanmak için bir öğretici var .
ssokolow

1
@YonatanSimson ElementTree yalnızca bir kodlama belirtirseniz itaat ediyor gibi göründüğünden, bu tam dizeyi nasıl ekleyeceğimi bilmiyorum xml_declaration=True... ancak, eşdeğer davranış elde etmek için şu şekilde çağırın tree.write(): tree.write("filename.xml", xml_declaration=True, encoding='utf-8')Açıkça belirttiğiniz sürece herhangi bir kodlamayı kullanabilirsiniz bir. ( asciidüzgün yapılandırılmış bir web sunucusuna güvenmiyorsanız 7 bit ASCII setinin dışındaki tüm Unicode karakterlerini varlık kodlu olmaya
zorlar

1
Düzeltmek için çalışır başkasına Sadece bir hatırlatma vlaue2için value2yazım hatası asıl soruya istenilen XML çıktısında geçerli:. Bu değişikliklerin kadar yazım hatası burada aslında olduğu doğru.
ssokolow

3
Belgelere göre , cElementTreePython 3.3 değer kaybetmiş oldu
Stevoisiak

63

Lxml kütüphanesi denilen XML nesil için çok uygun bir sözdizimi içerir e-fabrika . Verdiğiniz örneği şu şekilde yapacağım:

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

Çıktı:

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

Ayrıca, zaten yapılmış bir düğüme eklemeyi de destekler, örn.

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

3
Etiketin adı Python tanımlayıcı kurallarına uymuyorsa getattr, örneğin, kullanabilirsiniz getattr(E, "some-tag").
haridsv

benim için yazdır lxml.etree.tostring AttributeError neden oldu: 'lxml.etree._Element' nesnesi 'etree' özniteliğine sahip değil. "Lxml" yi başlatmadan çalıştı. like: etree.tostring (the_doc, pretty_print = Doğru)
kodlan

19

Yattag http://www.yattag.org/ veya https://github.com/leforestier/yattag , böyle bir XML belgesi (ve ayrıca HTML belgeleri) oluşturmak için ilginç bir API sağlar.

Bu kullanıyor bağlam yöneticisi ve withanahtar kelime.

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)

böylece alacaksınız:

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


4

Böyle basit bir XML yapısı için tam bir XML modülü dahil etmek istemeyebilirsiniz. En basit yapılar için bir dize şablonu veya biraz daha karmaşık bir şey için Jinja'yı düşünün. Jinja, belge listenizin iç xml'sini oluşturmak için bir veri listesi üzerinde döngü gerçekleştirebilir. Ham python dize şablonları ile biraz daha zor

Bir Jinja örneği için benzer bir soruya verdiğim cevaba bakınız .

Dize şablonlarıyla xml'nizi oluşturmanın bir örneği.

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

Çıktı:

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

Şablon yaklaşımının altını çizmek, kaçmaktan <ve >ücretsiz olarak elde etmemenizdir . Bir sorun çekerek bu sorunun etrafında dans ettimxml.sax


1

Bigh_29'un Şablonlar yöntemini kullanarak bir xml oluşturucu yazmayı bitirdim ... çok fazla Nesne 'yoluna' girmeden çıktılarınızı kontrol etmenin güzel bir yolu.

Etiket ve değere gelince, biri çıktı xml'de etiket adını ve konumunu veren diğerini aynı etiket listesine sahip bir parametre dosyasına başvuran iki dizi kullandım. Bununla birlikte parametre dosyası, verilerin alınacağı karşılık gelen giriş (csv) dosyasında da konum numarasına sahiptir. Bu şekilde, giriş dosyasından gelen verilerin pozisyonunda herhangi bir değişiklik olursa, program değişmez; parametre dosyasındaki uygun etiketten veri alanı konumunu dinamik olarak çalıştırır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.