簡體   English   中英

使用 Python 和 ElementTree 對 XML 文檔進行排序

[英]Sorting XML document with Python and ElementTree

我正在嘗試重新組織一些 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')

我認為,在您到達 xpath 3.1 之前,沒有真正的方法可以對 xml 進行排序,但有可能解決這個問題。

請注意,由於您問題中的 xml 無效(您有未聲明的命名空間),因此我使用了更寬容的 html 解析器。 對於您的實際代碼,您應該使用 xml 解析器,如下所示。

此代碼的作用是從每個<trkseg>父節點收集每個<name>子節點的節點值(即您的目標編號),將它們保存到列表中,對列表進行排序,再次使用排序列表 select <trkseg>節點,並使用它們(連同開始和結束標簽)創建一個新的 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)

Output:

<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>

Element object 可以被視為以子元素為成員的可迭代對象。 這使得對根元素的子元素進行排序變得容易。 在這種情況下,我們需要為第一個孩子 ( <name>GPSRoute.XML</name> ) 設置一個例外,它不參與排序。

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>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM