【问题标题】:Sorting XML document with Python and ElementTree使用 Python 和 ElementTree 对 XML 文档进行排序
【发布时间】:2020-04-24 03:34:22
【问题描述】:

我正在尝试重新组织一些 xml 文件,这些文件包含完整路由的多个部分,其结构如下:

<trk>
    <name>GPSRoute.XML</name>
    <trkseg>
        <trkpt lat="37.077882" lon="-112.242785">
            <ele>1688.00</ele>
            <time>2020-04-18T01:56:39.80Z</time>
        </trkpt>
        <extensions>
            <name>14</name>
            <gte:color>#00ce00</gte:color>
        </extensions>
    </trkseg>
    <trkseg>
        <trkpt lat="37.077888" lon="-112.242783">
            <ele>1688.00</ele>
            <time>2020-04-18T01:56:39.80Z</time>
        </trkpt>
        <extensions>
            <name>1</name>
            <gte:color>#00ce00</gte:color>
        </extensions>
    </trkseg>
</trk>

我正在尝试按名称而不是当前时间对文件进行排序,并将结果写入新文件。到目前为止,这就是我所取得的成就,它成功地捕获了列表中的名称,但它在 data.sort() 上出错:

“TypeError:'xml.etree.ElementTree.Element'和'xml.etree.ElementTree.Element'的实例之间不支持'

如果有人能指出我正确的方向,将不胜感激!

import xml.etree.ElementTree as ET

tree = ET.parse('Filename.xml')

root = tree.getroot()
data = []
for track in root:
    for segment in track:
        for extension in segment:
            for name in extension.findall('name'):
                print(name.text)
                data.append((name))
            data.sort()


tree.write('Sorted.xml')

【问题讨论】:

  • 你能添加预期的输出吗?

标签: python xml sorting xml-parsing elementtree


【解决方案1】:

我认为,在您使用 xpath 3.1 之前,没有真正的方法可以对 xml 进行排序,但您可以自行解决这个问题。

请注意,由于您问题中的 xml 无效(您有未声明的命名空间),因此我使用了更宽容的 html 解析器。对于您的实际代码,您应该使用 xml 解析器,如下所示。

此代码的作用是从每个&lt;trkseg&gt; 父节点收集每个&lt;name&gt; 子节点的节点值(即您的目标编号),将它们保存到列表中,对列表进行排序,使用排序后的列表再次按该排序顺序选择 &lt;trkseg&gt; 节点,并使用它们(连同开始和结束标签)创建一个新的 xml。

import lxml.html as lh # with actual xml you would probably use "from lxml import etree"
trk = """your xml above"""

doc = lh.fromstring(trk) # with actual xml you should probably use "doc = etree.XML(trk)"

names = []
new_trk = """<trk>
    <name>GPSRoute.XML</name>""" # this is the preamble which is left untouched
for nam in doc.xpath('//extensions//name'):
    names.append(nam.text) #grab the numbers
for name in sorted(names): #sort the grabbed numbers
    target = doc.xpath(f'//trkseg[.//name/text()={name}]')
    for t in target:
        new_trk += lh.tostring(t).decode()
new_trk += '</trk>' # append the closing tag, which is also left untouched
print(new_trk)

输出:

<trk>
    <name>GPSRoute.XML</name><trkseg>
        <trkpt lat="37.077888" lon="-112.242783">
            <ele>1688.00</ele>
            <time>2020-04-18T01:56:39.80Z</time>
        </trkpt>
        <extensions>
            <name>1</name>
            <color>#00ce00</color>
        </extensions>
    </trkseg>
<trkseg>
        <trkpt lat="37.077882" lon="-112.242785">
            <ele>1688.00</ele>
            <time>2020-04-18T01:56:39.80Z</time>
        </trkpt>
        <extensions>
            <name>14</name>
            <color>#00ce00</color>
        </extensions>
    </trkseg>
    </trk>

【讨论】:

    【解决方案2】:

    Element 对象可以被视为具有子元素作为成员的可迭代对象。这使得对根元素的子元素进行排序变得容易。在这种情况下,我们需要为第一个孩子(&lt;name&gt;GPSRoute.XML&lt;/name&gt;)做一个例外,它不参与排序。

    XML 文档中有一个未声明的命名空间前缀,因此我将gte:color 更改为color

    import xml.etree.ElementTree as ET
    
    tree = ET.parse('Filename.xml')
    root = tree.getroot()
    
    # Temporarily remove the 'name' element
    name = root.find("name")
    root.remove(name)
    
    # Sort the 'trkseg' elements using 'extensions/name' as key
    root[:] = sorted(root, key=lambda trkseg: int(trkseg.findtext("extensions/name")))
    
    # Put the 'name' element back
    root.insert(0, name)
    
    print(ET.tostring(root).decode())
    

    结果:

    <trk>
      <name>GPSRoute.XML</name>
      <trkseg>
        <trkpt lat="37.077888" lon="-112.242783">
          <ele>1688.00</ele>
          <time>2020-04-18T01:56:39.80Z</time>
        </trkpt>
        <extensions>
          <name>1</name>
          <color>#00ce00</color>
        </extensions>
      </trkseg>
    <trkseg>
        <trkpt lat="37.077882" lon="-112.242785">
          <ele>1688.00</ele>
          <time>2020-04-18T01:56:39.80Z</time>
        </trkpt>
        <extensions>
          <name>14</name>
          <color>#00ce00</color>
        </extensions>
      </trkseg>
      </trk>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-15
      相关资源
      最近更新 更多