Створення простого XML-файлу за допомогою python


161

Які мої варіанти, якщо я хочу створити простий XML-файл у python? (бібліотека)

Xml, який я хочу, виглядає так:

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

</root>

Відповіді:


310

В наші дні найпопулярнішим (і дуже простим) варіантом є API ElementTree , який включений у стандартну бібліотеку з Python 2.5.

Доступні варіанти для цього:

  • ElementTree (Основна, чисто-Python реалізація ElementTree. Частина стандартної бібліотеки з 2.5)
  • cElementTree (Оптимізована реалізація ElementTree C. Також пропонується у стандартній бібліотеці з 2.5)
  • LXML (на основі libxml2. Пропонує багатий набір API ElementTree, а також 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")

Я перевірив це, і він працює, але я припускаю, що пробіли не є істотними. Якщо вам потрібен відбіток «prettyprint», дайте мені знати, і я розберуся, як це зробити. (Це може бути специфічний для 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 для виведення, а не для введення.
ssokolow

1
@YonatanSimson Я не знаю, як додати цю точну рядок, оскільки, здається, ElementTree підкоряється лише xml_declaration=Trueтому, що ви вказали кодування ... але, щоб отримати еквівалентну поведінку, дзвоніть tree.write()так: tree.write("filename.xml", xml_declaration=True, encoding='utf-8')Ви можете використовувати будь-яке кодування до тих пір, поки ви чітко вказали один. ( asciiзмусить усіх символів Unicode поза 7-бітовим набором ASCII бути закодованим суттю, якщо ви не довіряєте веб-серверу правильно налаштованому.)
ssokolow

1
Тільки нагадування кому - або , хто намагається виправити vlaue2на value2: помилка в запитуваній виведення XML в вихідному питанні. До цього зміни, помилка тут на самому ділі не є правильною.
ssokolow

3
Згідно з документацією , cElementTreeбуло знецінено в Python 3.3
Stevoisiak

63

Бібліотека lxml включає дуже зручний синтаксис для генерації XML, який називається E-factory . Ось як я зробив приклад, який ви даєте:

#!/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
Якщо ім'я тега не відповідає правилам ідентифікаторів Python, то ви могли б використовувати getattr, наприклад, getattr(E, "some-tag").
haridsv

для мене print 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 . Він вбудований у стандартну бібліотеку python і його легко використовувати у простих випадках.

Ось досить простий у виконанні підручник: http://www.boddie.org.uk/python/XML_intro.html


6
Ця відповідь повинна містити приклад мінідуму, який використовується.
Stevoisiak

4

Для такої простої структури XML, можливо, ви не хочете залучати повноцінний модуль XML. Розгляньте шаблон рядка для найпростіших структур або Jinja для чогось трохи складнішого. Jinja може обробляти цикл переліку даних, щоб створити внутрішній xml вашого списку документів. Це трохи складніше з необробленими шаблонами рядків python

Для прикладу 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) файлі, з якого будуть взяті дані. Таким чином, якщо якісь зміни в положенні даних, що надходять із вхідного файлу, програма не змінюється; він динамічно опрацьовує позицію поля даних з відповідного тегу у файлі параметрів.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.