使用python创建一个简单的XML文件


161

如果我想在python中创建一个简单的XML文件,我有哪些选择?(明智的)

我想要的xml看起来像:

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

</root>

Answers:


310

如今,最受欢迎的(也是非常简单的)选项是ElementTree API,该元素自Python 2.5起已包含在标准库中。

可用的选项是:

  • ElementTree(ElementTree的基本,纯Python实现。自2.5以来是标准库的一部分)
  • cElementTree(ElementTree的优化C实现。从2.5开始在标准库中提供)
  • LXML(基于libxml2。提供ElementTree API的丰富超集以及XPath,CSS选择器等)

这是一个如何使用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 2014年

4
@nonsensickle您确实应该问一个新问题,然后给我发送一个链接到它,这样每个人都可以从中受益。但是,我会为您指明正确的方向。DOM(文档对象模型)库始终构建内存模型,因此您需要使用SAX(XML的简单API)实现。我从来没有研究过SAX的实现,但是这里是使用instdlib作为输出而不是输入的教程
ssokolow 2014年

1
@YonatanSimson我不知道如何添加该确切的字符串,因为ElementTree似乎仅xml_declaration=True在您指定编码的情况下服从...,但是,为了获得等效的行为,请tree.write()像这样调用:tree.write("filename.xml", xml_declaration=True, encoding='utf-8')只要您明确指定,就可以使用任何编码之一。(ascii如果您不信任正确配置的Web服务器,则会强制将7位ASCII设置之外的所有Unicode字符都进行实体编码。)
ssokolow

1
提醒所有其他想纠正此问题的vlaue2value2:错字在原始问题的请求XML输出中。在此之前,这里的错字实际上正确的。
ssokolow

3
根据文档cElementTree在Python 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
如果标签的名称不符合Python的标识符的规则,那么你可以使用getattr,例如,getattr(E, "some-tag")
haridsv

对我来说,打印lxml.etree.tostring导致AttributeError:'lxml.etree._Element'对象没有属性'etree'。它无需启动“ lxml”即可工作。像:etree.tostring(the_doc,pretty_print = True)
柯德兰

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>


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

我刚刚使用bigh_29的Templates方法编写了一个xml生成器,这是一种控制输出内容的好方法,而没有太多对象“阻碍”。

至于标签和值,我使用了两个数组,一个数组给出了标签名称和在输出xml中的位置,另一个数组引用了具有相同标签列表的参数文件。但是,参数文件在相应的输入(csv)文件中也有位置编号,将从中获取数据。这样,如果来自输入文件的数据位置发生任何变化,则程序不会改变;它可以从参数文件中的相应标签动态计算出数据字段的位置。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.