【问题标题】:Creaing XML file with a specific order or attributes using Python使用 Python 创建具有特定顺序或属性的 XML 文件
【发布时间】:2020-06-03 00:03:56
【问题描述】:

我正在尝试使用 lxml 创建一个 xml 文件,我很清楚 xml 中的属性顺序无关紧要,但我仍在寻找一种方法来防止属性按特定顺序排列。

我也尝试过 minidom,但也没有锻炼。

在 lxml 我有以下代码:

from lxml import etree as ET
from collections import OrderedDict
root = ET.Element("Root", OrderedDict([("id","0"),("start","0"),("end","200")]))
ET.tostring(root)

由于我在这里使用了 OrderedDict,因此这部分按我想要的顺序提供了以下属性输出:

<Root id="0" start="0" end="200"/>

然后我用同样的方法创建了一个 Child:

child1 = ET.Element("sentence", OrderedDict([("id","0"),("start","0"),("end","255")]))
root.append(child1)
xml_str = ET.tostring(root, pretty_print=True)
print(xml_str)

打印 xml_str 会得到我期望的输出:

<Root id="0" start="0" end="200">\n  <sentence id="0" start="0" end="255"/>\n</Root>

但是当涉及到将其写入 xml 文件时:

with open('op.xml', 'wb') as f:
  f.write(xml_str)

写入 op.xml 文件时输出不一样:

<?xml version="1.0"?>

<Root end="200" start="0" id="0">
       <sentence end="255" start="0" id="0"/>
</Root>

清楚地看到属性顺序已经改变,有什么方法可以得到我期望的输出,即保持属性顺序。

我也尝试过使用 minidom,但即使在参考以下内容后它也不起作用: Preserve order of attributes when modifying with minidom

【问题讨论】:

    标签: python xml lxml elementtree minidom


    【解决方案1】:

    这里是一个库,擅长提取数据,不太擅长修改XML文件,但也基本可以满足你的需求。

    from simplified_scrapy import SimplifiedDoc, utils, req
    doc = SimplifiedDoc("<Root></Root>")
    doc.Root.setAttrs({"id":"0","start":"0","end":"200"})
    doc.Root.setContent("<sentence />")
    doc.sentence.setAttrs({"id":"0","start":"0","end":"200"})
    utils.saveFile("op.xml",doc.html)
    

    结果:

    <Root id="0" start="0" end="200"><sentence id="0" start="0" end="200" /></Root>
    

    【讨论】:

    • 试过了,这也给出了属性顺序改变的xml,基本上没有提供预期的结果......&lt;Root end="200" start="0" id="0"&gt; &lt;sentence end="200" start="0" id="0"/&gt; &lt;/Root&gt;
    • @VipulkumarYadav 请确认。它按照输入字典的顺序拼写属性。
    • 对我之前的代码在问题中的工作是这样的:我将输出写入一个txt文件,在txt文件中,顺序保持不变,然后我更改了txt文件的扩展名到 xml,但是此解决方案仅适用于 Ubuntu,不适用于 windows
    • 太奇怪了。我在 mac 或 windows 上测试没有问题。
    【解决方案2】:

    使用 lxml.etree 使其工作:

    import lxml.etree
    from collections import OrderedDict
    
    root = lxml.etree.Element("Root", OrderedDict([("id","0"),("start","0"),("end","200")]))
    isVal = lxml.etree.SubElement(root, 'sentence', OrderedDict([("id","0"),("start","0"),("end","255")]))
    
    with open("xyz2.xml", 'wb') as f:
        f.write(lxml.etree.tostring(root, xml_declaration=True, encoding="utf-8"))
    
    print(open("xyz2.xml", 'r').read())
    

    输出:

    <?xml version='1.0' encoding='utf-8'?>
    <Root id="0" start="0" end="200"><sentence id="0" start="0" end="255"/></Root>
    

    【讨论】:

    • 看起来OrderedDict 不是必需的。对我来说,它适用于普通的dict。另请参阅stackoverflow.com/a/17654556/407651
    • @mzjn:是的,这是有道理的,因为 Python >= 3.7 保留了顺序
    • Python 中的 ElementTree >= 3.8 保留顺序。 stackoverflow.com/a/60176826/407651
    • 在 Python 中是>=3.8 元素树保留了顺序 - 已检查....... 但是在 windows 中生成 xml 时这甚至不起作用,可能是 windows 的一些问题或我的一些更改系统?具体......
    • 你的 Python 版本是多少?
    猜你喜欢
    • 1970-01-01
    • 2022-10-18
    • 2014-05-28
    • 1970-01-01
    • 2014-04-18
    • 2014-03-02
    • 1970-01-01
    • 2016-02-13
    • 1970-01-01
    相关资源
    最近更新 更多