Tạo một tệp XML đơn giản bằng python


160

Tùy chọn của tôi là gì nếu tôi muốn tạo một tệp XML đơn giản trong python? (thư viện thông thái)

Xml tôi muốn trông giống như:

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

</root>

Câu trả lời:


309

Ngày nay, tùy chọn phổ biến nhất (và rất đơn giản) là API ElementTree , đã được đưa vào thư viện chuẩn kể từ Python 2.5.

Các tùy chọn có sẵn cho đó là:

  • ElementTree (Cơ bản, triển khai Python thuần túy của ElementTree. Một phần của thư viện chuẩn từ 2.5)
  • cEuityTree (Tối ưu hóa triển khai C của ElementTree. Cũng được cung cấp trong thư viện chuẩn từ 2.5)
  • LXML (Dựa trên libxml2. Cung cấp một siêu bộ đệm API ElementTree phong phú cũng như XPath, Bộ chọn CSS và hơn thế nữa)

Đây là một ví dụ về cách tạo tài liệu mẫu của bạn bằng cách sử dụng cEuityTree trong st-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")

Tôi đã thử nó và nó hoạt động, nhưng tôi cho rằng khoảng trắng không đáng kể. Nếu bạn cần thụt "đẹp", hãy cho tôi biết và tôi sẽ tìm cách làm điều đó. (Đây có thể là một tùy chọn dành riêng cho LXML. Tôi không sử dụng triển khai stdlib nhiều)

Để đọc thêm, đây là một số liên kết hữu ích:

Như một lưu ý cuối cùng, cEuityTree hoặc LXML phải đủ nhanh cho tất cả các nhu cầu của bạn (cả hai đều được tối ưu hóa mã C), nhưng trong trường hợp bạn đang trong tình huống cần phải vắt kiệt mọi hiệu suất cuối cùng, các điểm chuẩn trên trang LXML chỉ ra rằng:

  • LXML rõ ràng giành chiến thắng để tuần tự hóa (tạo) XML
  • Là một tác dụng phụ của việc triển khai truyền tải cha mẹ thích hợp, LXML chậm hơn một chút so với cEuityTree để phân tích cú pháp.

1
@Kasper: Tôi không có máy Mac nên tôi không thể cố gắng sao chép vấn đề. Hãy cho tôi biết phiên bản Python và tôi sẽ xem liệu tôi có thể sao chép nó trên Linux không.
ssokolow

4
@nonsensickle Bạn thực sự nên hỏi một câu hỏi mới và sau đó gửi cho tôi một liên kết đến nó để mọi người có thể hưởng lợi từ nó. Tuy nhiên, tôi sẽ chỉ cho bạn đi đúng hướng. Các thư viện DOM (Mô hình đối tượng tài liệu) luôn xây dựng mô hình trong bộ nhớ để bạn muốn triển khai SAX (API đơn giản cho XML). Tôi chưa bao giờ xem xét các triển khai SAX nhưng đây là hướng dẫn sử dụng in-stdlib cho đầu ra thay vì đầu vào.
ssokolow

1
@YonatanSimson Tôi không biết cách thêm chuỗi chính xác đó , vì ElementTree dường như chỉ tuân theo xml_declaration=Truenếu bạn chỉ định mã hóa ... nhưng, để có hành vi tương đương, hãy gọi tree.write()như sau: tree.write("filename.xml", xml_declaration=True, encoding='utf-8')Bạn có thể sử dụng bất kỳ mã hóa nào miễn là bạn chỉ định rõ ràng một. ( asciisẽ buộc tất cả các ký tự Unicode bên ngoài ASCII 7 bit được đặt thành mã hóa thực thể nếu bạn không tin tưởng máy chủ web được định cấu hình đúng.)
ssokolow

1
Chỉ cần một lời nhắc nhở cho bất kỳ ai khác cố gắng sửa vlaue2thành value2: Lỗi đánh máy nằm trong đầu ra XML được yêu cầu trong câu hỏi ban đầu. Cho đến khi thay đổi, lỗi đánh máy ở đây thực sự chính xác.
ssokolow

3
Theo tài liệu , cElementTreeđã bị khấu hao trong Python 3.3
Stevoisiak

63

Các thư viện lxml bao gồm một cú pháp rất thuận lợi cho thế hệ XML, được gọi là E-nhà máy . Đây là cách tôi đưa ra ví dụ bạn đưa ra:

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

Đầu ra:

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

Nó cũng hỗ trợ thêm vào một nút đã được tạo, ví dụ như sau những điều trên bạn có thể nói

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

3
Nếu tên của thẻ không tuân theo quy tắc định danh Python, thì bạn có thể sử dụng getattr, ví dụ : getattr(E, "some-tag").
haridsv 30/03/2016

đối với tôi, in lxml.etree.tostring đã gây ra AttributionError: đối tượng 'lxml.etree._Euity' không có thuộc tính 'etree'. Nó hoạt động mà không bắt đầu "lxml." như: etree.tostring (the_doc, beautiful_print = True)
kodlan

19

Yattag http://www.yattag.org/ hoặc https://github.com/leforestier/yattag cung cấp một API thú vị để tạo tài liệu XML như vậy (và cả các tài liệu HTML).

Đó là sử dụng trình quản lý bối cảnhwithtừ khóa.

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)

vì vậy bạn sẽ nhận được:

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

6

Đối với sự lựa chọn đơn giản nhất, tôi sẽ đi với minidom: http://docs.python.org/l Library / xml.dom.minidom.html . Nó được tích hợp vào thư viện chuẩn python và rất dễ sử dụng trong các trường hợp đơn giản.

Đây là một hướng dẫn khá dễ thực hiện: http://www.boddie.org.uk/python/XML_intro.html


6
Câu trả lời này nên bao gồm một ví dụ về tối thiểu được sử dụng.
Stevoisiak

4

Đối với cấu trúc XML đơn giản như vậy, bạn có thể không muốn liên quan đến một mô-đun XML đầy đủ. Xem xét một mẫu chuỗi cho các cấu trúc đơn giản nhất hoặc Jinja cho một cái gì đó phức tạp hơn một chút. Jinja có thể xử lý việc lặp qua danh sách dữ liệu để tạo xml bên trong danh sách tài liệu của bạn. Đó là một chút phức tạp hơn với các mẫu chuỗi python thô

Để biết ví dụ về Jinja, hãy xem câu trả lời của tôi cho một câu hỏi tương tự .

Dưới đây là một ví dụ về việc tạo xml của bạn với các mẫu chuỗ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

Đầu ra:

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

Điểm mấu chốt của cách tiếp cận mẫu là bạn sẽ không thoát khỏi <>miễn phí. Tôi đã nhảy xung quanh vấn đề đó bằng cách sử dụngxml.sax


1

Tôi vừa viết xong một trình tạo xml, sử dụng phương thức Mẫu của bigh_29 ... đó là một cách hay để kiểm soát những gì bạn xuất ra mà không có quá nhiều Đối tượng nhận được 'theo cách'.

Đối với thẻ và giá trị, tôi đã sử dụng hai mảng, một mảng cung cấp tên và vị trí của thẻ trong xml đầu ra và một mảng khác tham chiếu một tệp tham số có cùng danh sách các thẻ. Tuy nhiên, tệp tham số cũng có số vị trí trong tệp đầu vào (csv) tương ứng nơi dữ liệu sẽ được lấy từ đó. Theo cách này, nếu có bất kỳ thay đổi nào đối với vị trí của dữ liệu đến từ tệp đầu vào, chương trình sẽ không thay đổi; nó tự động làm việc ra vị trí trường dữ liệu từ thẻ thích hợp trong tệp tham số.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.