การสร้างไฟล์ XML อย่างง่ายโดยใช้ python


161

ตัวเลือกของฉันคืออะไรหากฉันต้องการสร้างไฟล์ XML อย่างง่ายใน python (ห้องสมุดฉลาด)

xml ที่ฉันต้องการดูเหมือน:

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

</root>

คำตอบ:


310

วันนี้ตัวเลือกที่ได้รับความนิยมมากที่สุด (และง่ายมาก) คือElementTree APIซึ่งรวมอยู่ในไลบรารีมาตรฐานตั้งแต่ Python 2.5

ตัวเลือกที่ใช้ได้สำหรับ:

  • ElementTree (การใช้งานพื้นฐานแบบ pure-Python ของ ElementTree ส่วนหนึ่งของไลบรารีมาตรฐานตั้งแต่ 2.5)
  • cElementTree (การปรับใช้ C ที่เหมาะสมของ ElementTree และยังมีอยู่ในไลบรารีมาตรฐานตั้งแต่ 2.5)
  • LXML (ขึ้นอยู่กับ libxml2 เสนอ superset มากมายของ ElementTree API เช่น XPath, CSS Selectors และอื่น ๆ )

นี่คือตัวอย่างของวิธีการสร้างเอกสารตัวอย่างของคุณโดยใช้ 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")

ฉันทดสอบแล้วและใช้งานได้ แต่ฉันคิดว่าช่องว่างไม่สำคัญ หากคุณต้องการการเยื้อง "สวย" แจ้งให้เราทราบและฉันจะค้นหาวิธีการทำ (อาจเป็นตัวเลือกเฉพาะ LXML ฉันไม่ได้ใช้ stdlib มาก)

สำหรับการอ่านเพิ่มเติมนี่คือลิงค์ที่มีประโยชน์:

ในฐานะโน้ตสุดท้าย cElementTree หรือ LXML ควรเร็วพอสำหรับทุกความต้องการของคุณ (ทั้งคู่เป็นรหัส C ที่ปรับให้เหมาะสมที่สุด) แต่ในกรณีที่คุณอยู่ในสถานการณ์ที่คุณจำเป็นต้องบีบประสิทธิภาพทุกบิตให้เป็นมาตรฐาน ไซต์ LXML ระบุว่า:

  • LXML ชนะอย่างชัดเจนสำหรับการทำให้เป็นอันดับ XML (สร้าง)
  • ในฐานะที่เป็นผลข้างเคียงของการใช้การสำรวจเส้นทางหลักที่เหมาะสม LXML ช้ากว่า cElementTree เล็กน้อยในการแยกวิเคราะห์

1
@Kasper: ฉันไม่มี Mac ดังนั้นฉันจึงไม่สามารถลองทำซ้ำปัญหาได้ บอกรุ่น Python ให้ฉันหน่อยและฉันจะดูว่าฉันสามารถทำซ้ำบน Linux ได้หรือไม่
ssokolow

4
@nonsensickle คุณควรถามคำถามใหม่แล้วส่งลิงก์มาให้ฉันเพื่อให้ทุกคนได้รับประโยชน์จากมัน อย่างไรก็ตามฉันจะชี้ให้คุณในทิศทางที่ถูกต้อง ไลบรารี DOM (Document Object Model) จะสร้างโมเดลในหน่วยความจำเสมอดังนั้นคุณจึงต้องการการประยุกต์ใช้ SAX (Simple API สำหรับ XML) แทน ฉันไม่เคยตรวจสอบการใช้งาน SAX แต่นี่เป็นบทแนะนำสำหรับการใช้in-stdlib oneสำหรับเอาท์พุตมากกว่าอินพุต
ssokolow

1
@YonatanSimson ฉันไม่ทราบวิธีการเพิ่มสตริงที่แน่นอนเนื่องจาก ElementTree ดูเหมือนว่าจะเชื่อฟังเฉพาะxml_declaration=Trueถ้าคุณระบุการเข้ารหัส ... แต่เพื่อให้ได้พฤติกรรมที่เทียบเท่าโทรtree.write()เช่นนี้: tree.write("filename.xml", xml_declaration=True, encoding='utf-8')คุณสามารถใช้การเข้ารหัสใด ๆ ตราบเท่าที่คุณระบุอย่างชัดเจน หนึ่ง. ( asciiจะบังคับให้อักขระ Unicode ทั้งหมดที่อยู่นอกชุด ASCII 7 บิตถูกเข้ารหัสเป็นเอนทิตีหากคุณไม่เชื่อถือเว็บเซิร์ฟเวอร์ที่จะกำหนดค่าอย่างถูกต้อง)
ssokolow

1
เพียงแค่เตือนให้คนอื่นที่พยายามที่จะแก้ไขให้ถูกต้องvlaue2เพื่อvalue2การพิมพ์ผิดอยู่ในการส่งออก XML ร้องขอในคำถามเดิม จนกระทั่งมีการเปลี่ยนแปลงที่พิมพ์ผิดจริงที่นี่เป็นที่ถูกต้อง
ssokolow

3
ตามเอกสาร , cElementTreeถูกตัดค่าเสื่อมราคาในหลาม 3.3
Stevoisiak

63

ห้องสมุด lxmlรวมถึงไวยากรณ์สะดวกมากสำหรับการสร้าง XML ที่เรียกว่าE-โรงงาน นี่คือวิธีที่ฉันทำตัวอย่างที่คุณให้:

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

เอาท์พุท:

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

นอกจากนี้ยังรองรับการเพิ่มไปยังโหนดที่ทำไว้แล้วเช่นหลังจากข้างต้นคุณสามารถพูดได้

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

3
หากชื่อของแท็กไม่เป็นไปตามกฎระเบียบที่ระบุงูใหญ่แล้วคุณสามารถใช้เช่นgetattr getattr(E, "some-tag")
haridsv

สำหรับฉันพิมพ์ lxml.etree.tostring ก่อให้เกิด AttributeError: 'lxml.etree._Element' วัตถุไม่มีแอตทริบิวต์ 'etree' มันทำงานโดยไม่เริ่มต้น "lxml" ไลค์: etree.tostring (the_doc, pretty_print = True)
kodlan

19

Yattag http://www.yattag.org/หรือhttps://github.com/leforestier/yattagจัดทำ API ที่น่าสนใจในการสร้างเอกสาร XML ดังกล่าว (และเอกสาร HTML)

กำลังใช้ตัวจัดการบริบทและ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)

ดังนั้นคุณจะได้รับ:

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

6

สำหรับทางเลือกที่ง่ายที่สุดฉันไปกับ minidom: http://docs.python.org/library/xml.dom.minidom.html มันถูกสร้างขึ้นในไลบรารีมาตรฐานหลามและตรงไปตรงมาเพื่อใช้ในกรณีง่าย ๆ

ต่อไปนี้เป็นบทแนะนำที่ใช้งานง่าย: http://www.boddie.org.uk/python/XML_intro.html


6
คำตอบนี้ควรมีตัวอย่างของ minidom ที่ใช้งานอยู่
Stevoisiak

4

สำหรับโครงสร้าง XML อย่างง่ายคุณอาจไม่ต้องการเกี่ยวข้องกับโมดูล XML แบบเต็ม พิจารณาเทมเพลตสตริงสำหรับโครงสร้างที่ง่ายที่สุดหรือ Jinja สำหรับบางสิ่งที่ซับซ้อนกว่าเล็กน้อย Jinja สามารถจัดการวนรอบรายการข้อมูลเพื่อสร้าง XML ภายในของรายการเอกสารของคุณ นั่นเป็นเรื่องยุ่งยากเล็กน้อยกับแม่แบบสตริงหลามดิบ

สำหรับตัวอย่างที่ Jinja ดูของฉันคำตอบให้กับคำถามที่คล้ายกัน

นี่คือตัวอย่างของการสร้าง xml ของคุณด้วยแม่แบบสตริง

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

เอาท์พุท:

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

ข้อเสียของเทมเพลตคือคุณจะไม่หลุดพ้นจาก<และ>ฟรี ฉันเต้นไปรอบ ๆ ปัญหานั้นโดยการดึงประโยชน์จากxml.sax


1

ฉันเพิ่งเขียนตัวสร้าง xml เสร็จโดยใช้วิธีการของแม่แบบ bigh_29 ... มันเป็นวิธีที่ดีในการควบคุมสิ่งที่คุณส่งออกโดยไม่ต้องมีวัตถุมากเกินไปที่จะ 'เข้ามา'

สำหรับแท็กและค่าฉันใช้สองอาร์เรย์หนึ่งอันซึ่งให้ชื่อแท็กและตำแหน่งในเอาต์พุต xml และอีกอันหนึ่งซึ่งอ้างอิงไฟล์พารามิเตอร์ที่มีรายการแท็กเดียวกัน อย่างไรก็ตามไฟล์พารามิเตอร์ยังมีหมายเลขตำแหน่งในไฟล์อินพุต (csv) ที่สอดคล้องกันซึ่งข้อมูลจะถูกนำมาจาก ด้วยวิธีนี้หากมีการเปลี่ยนแปลงตำแหน่งของข้อมูลที่เข้ามาจากไฟล์อินพุตโปรแกรมจะไม่เปลี่ยนแปลง มันทำงานออกจากตำแหน่งของเขตข้อมูลจากแท็กที่เหมาะสมในไฟล์พารามิเตอร์แบบไดนามิก

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.