如何在Python中打开这个XML文件并创建数据框?

9
有没有人有建议,最好的方法打开下面网站上的xml数据,将其放入python中的dataframe中(我更喜欢使用pandas)?该文件位于此网站上的“Data-XML(sdmx / zip)”链接上:http://www.federalreserve.gov/pubs/feds/2006/200628/200628abs.html。我已经尝试过从http://timhomelab.blogspot.com/2014/01/how-to-read-xml-file-into-dataframe.html复制以下内容,看起来我接近成功了:
from lxml import objectify
import pandas as pd

path = 'feds200628.xml'
xml = objectify.parse(open(path))
root = xml.getroot()
root.getchildren()[0].getchildren()
df = pd.DataFrame(columns=('id', 'name'))

for i in range(0,4):
    obj = root.getchildren()[i].getchildren()
    row = dict(zip(['id', 'name'], [obj[0].text, obj[1].text]))
    row_s = pd.Series(row)
    row_s.name = i
    df = df.append(row_s)

然而,我对XML的了解还不够,无法完成剩余的部分。

任何帮助都将是极好的 - 我甚至不需要它在数据框中,我只需要找出如何以某种方式在Python中解析此内容。


可能是如何在Python中打开Excel文件?的重复问题。 - poolie
3个回答

10

XML是一种类似树形结构的内容,而Pandas DataFrame则是一种类似二维表格的结构。因此,两者之间没有自动转换的方法。您必须了解XML结构,并知道如何将其数据映射到二维表格上。 因此,每个XML到DataFrame的问题都是不同的。

您的XML具有2个数据集,每个数据集包含多个系列。每个系列包含多个观察元素。

每个系列都具有名称(NAME)属性,而每个观测值(Obs)都具有OBS_STATUS、TIME_PERIOD和OBS_VALUE属性。因此,创建一个带有NAME、OBS_STATUS、TIME_PERIOD和OBS_VALUE列的表格可能是合理的。

我发现从XML中提取所需数据有点复杂,这让我怀疑我是否已经找到了最好的方法。但以下是其中一种方法(附注:Thomas Maloney的思路从类似二维表格的XLS数据开始应该更简单):

import lxml.etree as ET
import pandas as pd

path = 'feds200628.xml'

def fast_iter(context, func, *args, **kwargs):
    """
    http://lxml.de/parsing.html#modifying-the-tree
    Based on Liza Daly's fast_iter
    http://www.ibm.com/developerworks/xml/library/x-hiperfparse/
    See also http://effbot.org/zone/element-iterparse.htm
    https://dev59.com/pGw05IYBdhLWcg3wiyfg#7171543 (unutbu)
    """
    for event, elem in context:
        func(elem, *args, **kwargs)
        # It's safe to call clear() here because no descendants will be
        # accessed
        elem.clear()
        # Also eliminate now-empty references from the root node to elem
        for ancestor in elem.xpath('ancestor-or-self::*'):
            while ancestor.getprevious() is not None:
                del ancestor.getparent()[0]
    del context

data = list()
obs_keys = ['OBS_STATUS', 'TIME_PERIOD', 'OBS_VALUE']
columns = ['NAME'] + obs_keys

def process_obs(elem, name):
    dct = elem.attrib
    # print(dct)
    data.append([name] + [dct[key] for key in obs_keys])

def process_series(elem):
    dct = elem.attrib
    # print(dct)
    context = ET.iterwalk(
        elem, events=('end', ),
        tag='{http://www.federalreserve.gov/structure/compact/common}Obs'
        )
    fast_iter(context, process_obs, dct['SERIES_NAME'])

def process_dataset(elem):
    nsmap = elem.nsmap
    # print(nsmap)
    context = ET.iterwalk(
        elem, events=('end', ),
        tag='{{{prefix}}}Series'.format(prefix=elem.nsmap['kf'])
        )
    fast_iter(context, process_series)

with open(path, 'rb') as f:
    context = ET.iterparse(
        f, events=('end', ),
        tag='{http://www.federalreserve.gov/structure/compact/common}DataSet'
        )
    fast_iter(context, process_dataset)
    df = pd.DataFrame(data, columns=columns)
产生收益
            NAME OBS_STATUS TIME_PERIOD   OBS_VALUE
0        SVENY01          A  1961-06-14      2.9825
1        SVENY01          A  1961-06-15      2.9941
2        SVENY01          A  1961-06-16      3.0012
3        SVENY01          A  1961-06-19      2.9949
4        SVENY01          A  1961-06-20      2.9833
5        SVENY01          A  1961-06-21      2.9993
6        SVENY01          A  1961-06-22      2.9837
...
1029410     TAU2          A  2014-09-19  3.72896779
1029411     TAU2          A  2014-09-22  3.12836171
1029412     TAU2          A  2014-09-23  3.20146575
1029413     TAU2          A  2014-09-24  3.29972110

6
我会将XLS格式文件导出为CSV文件(使用免费的程序,如Gnumeric或LibreOffice,或如果您有Excel),然后将CSV文件读入pandas。我知道这不完全是你最终问题的答案,但解析XML是对你所尝试做的事情过于复杂的解决方案。
关于在Python中解析XML,lxml库是我最喜欢使用的库。我发现使用XPath查询语言和lxml解析器是最好的方法。

-1

这段代码可以将这种类型的Excel XML文件转换为df:

import pandas as pd
from xml.sax import ContentHandler, parse

# Reference https://goo.gl/KaOBG3
class ExcelHandler(ContentHandler):
    def __init__(self):
        self.chars = [  ]
        self.cells = [  ]
        self.rows = [  ]
        self.tables = [  ]
    def characters(self, content):
        self.chars.append(content)
    def startElement(self, name, atts):
        if name=="Cell":
            self.chars = [  ]
        elif name=="Row":
            self.cells=[  ]
        elif name=="Table":
            self.rows = [  ]
    def endElement(self, name):
        if name=="Cell":
            self.cells.append(''.join(self.chars))
        elif name=="Row":
            self.rows.append(self.cells)
        elif name=="Table":
            self.tables.append(self.rows)

excelHandler = ExcelHandler()
parse('feds200628.xls', excelHandler)
df1 = pd.DataFrame(excelHandler.tables[0][10:], columns=excelHandler.tables[0][9])
print df1.head()

我因声望不足而无法发表评论,但是关于“如何使用Python和Pandas编程打开Excel XML文件”的这个问题的答案应该是有效的。


这并没有为问题提供答案。如果需要对作者进行批评或请求澄清,请在他们的帖子下留言 - 您始终可以对自己的帖子发表评论,并且一旦您拥有足够的声望,您将能够评论任何帖子 - UmNyobe
@UmNyobe 好的,我已经添加了代码。我只是更改了文件名和数据开始的行数。 - jrovegno

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接