【问题标题】:Creating a simple XML file using python使用 python 创建一个简单的 XML 文件
【发布时间】:2011-04-06 01:29:36
【问题描述】:

如果我想在 python 中创建一个简单的 XML 文件,我有哪些选择? (图书馆方面)

我想要的xml看起来像:

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

</root>

【问题讨论】:

    标签: python xml


    【解决方案1】:

    对于最简单的选择,我会选择 minidom:http://docs.python.org/library/xml.dom.minidom.html。它内置在 python 标准库中,在简单的情况下使用起来很简单。

    这是一个非常容易上手的教程:http://www.boddie.org.uk/python/XML_intro.html

    【讨论】:

    • 这个答案应该包括一个使用中的 minidom 的例子。
    【解决方案2】:

    如今,最流行(也非常简单)的选项是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 实现)

    为了进一步阅读,这里有一些有用的链接:

    最后一点,cElementTree 或 LXML 的速度应该足以满足您的所有需求(两者都是经过优化的 C 代码),但如果您处于需要挤出最后一点性能的情况, LXML 网站上的基准表明:

    • LXML 在序列化(生成)XML 方面明显胜出
    • 作为实现正确父遍历的副作用,LXML 在解析方面比 cElementTree 慢一些。

    【讨论】:

    • @Kasper:我没有 Mac,所以无法尝试复制问题。告诉我 Python 版本,我看看能否在 Linux 上复制它。
    • @nonsensickle 你真的应该问一个新问题,然后给我发一个链接,这样每个人都可以从中受益。但是,我会为您指明正确的方向。 DOM(文档对象模型)库始终构建内存模型,因此您需要 SAX(XML 的简单 API)实现。我从未研究过 SAX 实现,但这里有一个 tutorial 用于使用 in-stdlib one 进行输出而不是输入。
    • @YonatanSimson 我不知道如何添加那个 exact 字符串,因为 ElementTree 似乎只有在指定编码时才服从xml_declaration=True...但是,要获得等效行为,请像这样调用tree.write()tree.write("filename.xml", xml_declaration=True, encoding='utf-8') 只要您明确指定一个,您就可以使用任何编码。 (如果您不相信 Web 服务器配置正确,ascii 将强制 7 位 ASCII 集之外的所有 Unicode 字符进行实体编码。)
    • 提醒任何尝试将vlaue2 更正为value2 的人:错字出现在原始问题中请求的XML 输出中。在这种情况发生变化之前,这里的错字实际上正确的。
    • According to the documentation, cElementTree 在 Python 3.3 中被贬值了
    【解决方案3】:

    lxml library 包含一种非常方便的 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'))
    

    【讨论】:

    • 如果标签名称不符合 Python 标识符规则,则可以使用getattr,例如getattr(E, "some-tag")
    • 对我来说打印 lxml.etree.tostring 导致 AttributeError:'lxml.etree._Element' 对象没有属性 'etree'。它在没有启动“lxml”的情况下工作。比如:etree.tostring(the_doc, pretty_print=True)
    【解决方案4】:

    Yattag http://www.yattag.org/https://github.com/leforestier/yattag 提供了一个有趣的 API 来创建此类 XML 文档(以及 HTML 文档)。

    它使用了context managerwith 关键字。

    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>
    

    【讨论】:

    • 这是一种非常干净的方式来生成标记。我敢说它比任何内置方式都更 Pythonic。
    【解决方案5】:

    对于这样一个简单的 XML 结构,您可能不想涉及一个成熟的 XML 模块。考虑为最简单的结构使用字符串模板,或为更复杂的结构考虑 Jinja。 Jinja 可以处理循环数据列表以生成文档列表的内部 xml。使用原始 python 字符串模板有点棘手

    有关 Jinja 的示例,请参阅我的 answer to a similar question

    这是使用字符串模板生成 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>
    

    模板方法的缺点是您不会免费转义&lt;&gt;。我通过从xml.sax 拉入一个实用程序来解决这个问题

    【讨论】:

      【解决方案6】:

      我刚写完一个 xml 生成器,使用 bigh_29 的模板方法...这是一种控制输出内容的好方法,不会有太多对象“妨碍”。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-03-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-02
        • 2016-12-18
        • 1970-01-01
        相关资源
        最近更新 更多