【问题标题】:Flattening nested XML whilst maintaining parent child relationship between two tags展平嵌套的 XML,同时保持两个标签之间的父子关系
【发布时间】:2020-08-20 19:31:43
【问题描述】:

我有一些带有嵌套属性的 xml

<Music>
  <Groups>
    <Artist>The Beatles</Artist>
    <Releases>
      <Release album="Abbey Road" year="1969" />
      <Release album="The White Album" year="1968" />
    </Releases>
  </Groups>
  <Groups>
    <Artist>Bob Dylan</Artist>
    <Releases>
      <Release album="Blonde on Blonde" year="1966" />
      <Release album="Blood on the Tracks" year="1975" />
    </Releases>
  </Groups>
  <Groups>
    <Artist>The Rolling Stones</Artist>
    <Releases>
      <Release album="Sticky Fingers" year="1971" />
      <Release album="Exile On Main Street" year="1972" />
    </Releases>
  </Groups>
</Music>

我正在尝试取回一个六行数据框,但是它创建了多对多关系,其中每个艺术家都被分配到每个专辑。这是我的代码以及我的错误结果:

import xml.etree.cElementTree as et
import pandas as pd

tree=et.parse(r'music.xml')
root=tree.getroot()

Artists=[]
AlbumTitle=[]
ReleaseYear=[]

for x in root.iter('Artist'):
    root1=et.Element('root')
    root1=x
    for records in root.iter('Release'):
        root2=et.Element('root')
        root2=records
        AlbumTitle.append(records.attrib['album'])
        ReleaseYear.append(records.attrib['year'])
        Artists.append(x.text)

df = pd.DataFrame({'Artists': Artists, 
                   'AlbumTitle': AlbumTitle,
                   'ReleaseYear': ReleaseYear})

Current output:

Artists                         AlbumTitle          ReleaseYear
-------                         -----------           -----         
1   The Beatles                 Abbey Road              1969
2   The Beatles                 The White album         1968
3   The Beatles                 Blonde On Blonde        1966
4   The Beatles                 Blood on The tracks     1975
5   The Beatles                 Sticky Fingers          1971
6   The Beatles                 Exile On Main Street    1972
7   Bob Dylan                   Abbey Road              1969
8   Bob Dylan                   The White album         1968
...                             ...                     ...
18  The Rolling Stones          Exile On Main Street    1972 


Target output:

Artists               AlbumTitle            ReleaseYear
-------               -----------           -----           
1 The Beatles         Abbey Road            1969
2 The Beatles         The White album       1968
3 Bob Dylan           Blonde On Blonde      1966
4 Bob Dylan           Blood on The tracks   1975
5 The Rolling Stones  Sticky Fingers        1971
6 The Rolling Stones  Exile On Main Street  1972

我阅读了 ElementTree 文档以了解 Artists.append 如何与这两个属性建立严格的关系,但到目前为止还没有运气。任何帮助将不胜感激,谢谢

【问题讨论】:

  • 你的 root1root2 行是多余的。

标签: python xml pandas elementtree


【解决方案1】:

这应该适合你:

import xml.etree.cElementTree as et
import pandas as pd

tree=et.parse(r'music.xml')
root=tree.getroot()

Artists=[]
AlbumTitle=[]
ReleaseYear=[]

for group in root.iter('Groups'):
    # Groups
    artist = group[0].text
    releases = group[1]
    for release in releases:
        Artists.append(artist)
        AlbumTitle.append(release.attrib['album'])
        ReleaseYear.append(release.attrib['year'])

df = pd.DataFrame({'Artists': Artists,
                   'AlbumTitle': AlbumTitle,
                   'ReleaseYear': ReleaseYear})

这是关于如何解析 xml (https://docs.python.org/3.4/library/xml.etree.elementtree.html) 的文档

输出:

              Artists            AlbumTitle ReleaseYear
0         The Beatles            Abbey Road        1969
1         The Beatles       The White Album        1968
2           Bob Dylan      Blonde on Blonde        1966
3           Bob Dylan   Blood on the Tracks        1975
4  The Rolling Stones        Sticky Fingers        1971
5  The Rolling Stones  Exile On Main Street        1972

【讨论】:

    【解决方案2】:
    import xml.etree.ElementTree as ET
    #i wrapped the xml into a 'data' variable in string form
    #since u r reading it from a file getroot should suffice : 
    #root = ET.parse(xmlfile).getroot()
    
    root = ET.fromstring(data)  
    
    d = []
    #the main point is the 'Groups' section
    for ent in root.findall('Groups'):
        #get the Artist names
        name = ent.find('Artist').text
        #append each entry in the Release section :
        for entry in ent.findall('.//Release'):
            #add a name key with the artist name to each entry
            entry.attrib.update({'name':name})
            d.append(entry.attrib)
    
    #get dataframe
    #u can rename the columns to ur taste
    pd.DataFrame(d)
    
           album                year    name
    0   Abbey Road              1969    The Beatles
    1   The White Album         1968    The Beatles
    2   Blonde on Blonde        1966    Bob Dylan
    3   Blood on the Tracks     1975    Bob Dylan
    4   Sticky Fingers          1971    The Rolling Stones
    5   Exile On Main Street    1972    The Rolling Stones
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-05
      • 1970-01-01
      • 2014-09-15
      • 1970-01-01
      • 1970-01-01
      • 2020-06-01
      • 2022-06-11
      相关资源
      最近更新 更多