如果我想用python创建一个简单的XML文件,我有什么选择?(图书馆明智)
我想要的xml看起来像:
<root>
<doc>
<field1 name="blah">some value1</field1>
<field2 name="asdfasd">some vlaue2</field2>
</doc>
</root>
如果我想用python创建一个简单的XML文件,我有什么选择?(图书馆明智)
我想要的xml看起来像:
<root>
<doc>
<field1 name="blah">some value1</field1>
<field2 name="asdfasd">some vlaue2</field2>
</doc>
</root>
对于最简单的选择,我会选择minidom: http://docs.python.org/library/xml.dom.minidom.html。它内置在python标准库中,在简单的情况下可以直接使用。
这里有一个非常简单的教程:http://www.boddie.org.uk/python/XML_intro.html
现在,最流行(也非常简单)的选项是ElementTree API, 它自Python 2.5起就被包含在标准库中。
可用的选项有:
ElementTree (ElementTree的基本、纯python实现。2.5以后的标准库的一部分) cElementTree (ElementTree的优化C实现。从2.5开始在标准库中也提供了。已弃用,并在3.3中将其折叠到常规的ElementTree中作为一个自动的东西。) LXML(基于libxml2。提供了丰富的ElementTree API超集以及XPath、CSS选择器等)
下面是如何使用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实现)
为了进一步阅读,这里有一些有用的链接:
在Python标准库中实现的API文档 入门教程(来自原作者的网站) LXML树教程。(带有从所有主要ElementTree实现中加载最佳可用选项的示例代码)
最后要注意的是,cElementTree或LXML都应该足够快来满足你的所有需求(两者都是优化的C代码),但如果你处于需要挤出最后一点性能的情况下,LXML站点上的基准测试表明:
LXML显然在序列化(生成)XML方面更胜一筹 作为实现适当的父遍历的副作用,LXML在解析时比cElementTree慢一些。
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'))
Yattag http://www.yattag.org/或https://github.com/leforestier/yattag提供了一个有趣的API来创建这样的XML文档(以及HTML文档)。
它使用上下文管理器和带关键字。
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>
对于这样一个简单的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 <value> for the <bar> document</field2>
</doc>
</root>
模板方法的缺点是不能免费获得<和>的转义。我从xml.sax中引入了一个util,绕过了这个问题
我刚刚写完一个xml生成器,使用bigh_29的方法的模板…这是一种很好的方式来控制你的输出没有太多的对象得到“在路上”。
As for the tag and value, I used two arrays, one which gave the tag name and position in the output xml and another which referenced a parameter file having the same list of tags. The parameter file, however, also has the position number in the corresponding input (csv) file where the data will be taken from. This way, if there's any changes to the position of the data coming in from the input file, the program doesn't change; it dynamically works out the data field position from the appropriate tag in the parameter file.