【问题标题】:Dynamic search through xml attributes using lxml and xpath in python在python中使用lxml和xpath动态搜索xml属性
【发布时间】:2013-06-05 15:06:43
【问题描述】:

我正在努力将下一个 xml 数据移动到分层数据框中。由于对 SO 的帮助,我能够从 xml 中获取所有数据。但是,现在,我正在努力清理我提取的数据并在输出之前对其进行整形,因为我将这样做数千次。

更新:这是我最终想要的。我似乎无法动态获取TimeTimevalue。每个文件的频道名称都会改变。

channel = txt1[0](对于这个文件,txt1[0]="blah")到当channel = txt1[8](对于这个文件,txt1[8]="lir"

    channel      Time                    value
0     blah     2013-05-01 00:00:00    258
1     blah     2013-05-01 00:01:00    259
...
n-2   lir      2013-05-01 23:57:00    58
n-1   lir      2013-05-01 23:58:00    37
n     lir      2013-05-01 23:59:00    32

这是我的 xml 文件的获取和结构方式:

import requests
from lxml import etree, objectify
r = requests.get('https://api.stuff.us/place/getData?   security_key=key&period=minutes&startTime=2013-05-01T00:00&endTime=2013-05-01T23:59&sort=channel') #edited for privacy
root = etree.fromstring(r.text)
xml_new = etree.tostring(root, pretty_print=True)
print xml_new[300:900] #gives xml output to show structure
<startTime>2013-05-01 00:00:00</startTime>
<endTime>2013-05-01 23:59:00</endTime>
<summaryPeriod>minutes</summaryPeriod>
<data>
  <channel channel="97925" name="blah"> 
    <Time Time="2013-05-01 00:00:00">
      <value>258</value>
    </Time>
    <Time Time="2013-05-01 00:01:00">
      <value>259</value>
    </Time>
    <Time Time="2013-05-01 00:02:00">
      <value>258</value>
    </Time>
    <Time Time="2013-05-01 00:03:00">
      <value>257</value>
    </Time>

昨天,我在 SO 上询问并解决了将 timevalue 值放入数据框的问题:Parsing xml to pandas data frame throws memory error

dTime=[]
dvalue=[]
for df in root.xpath('//channel/Time'):
    ## Iterate over attributes of Time but Time only has one attrib [@Time]
    for attrib in df.attrib:
    dTime.append(df.attrib[attrib])
    ## value is a child of time, and iterate
    subfields = df.getchildren()
    for subfield in subfields:
    dvalue.append(subfield.text)
pef=DataFrame({'Time':dTime,'values':dvalue})

pef

&ltclass 'pandas.core.frame.DataFrame'&gt
Int64Index: 12960 entries, 0 to 12959
Data columns (total 2 columns):
Time     12960  non-null values
value    12960  non-null values
dtypes: object(2) 

pef[:5]

    Time                    value
0    2013-05-01 00:00:00    258
1    2013-05-01 00:01:00    259
2    2013-05-01 00:02:00    258
3    2013-05-01 00:03:00    257
4    2013-05-01 00:04:00    257

现在,我正在为每个通道(结构为 channel -> Time -> value)分别处理此数据,以便我可以将通道作为数据集的列插入.

所以,我决定动态获取频道名称,并在数据中进行搜索。对于这个文件,有九个单独的有效频道名称,但对于所有文件(编号或名称)并不相同。

txt1 = root.xpath('//channel/@name') #this prints all channel names!
len(txt1)
Out[67]: 9
print txt1
['blah', 'b', 'c', 'd', 'vd', 'ef', 'fg', 'kc', 'lir']

我认为我可以动态获取数据(使用早期的解决方案,但添加@name=txt1[0])并最终执行for i = 0 to len(txt1), ... 来遍历所有数据。但我得到一个空数据框:

dTime=[]
dchannel = txt1[0] # can hardcode, but need to be able to get all
dvalue=[]
for df in root.xpath('//channel[@name=txt1[0]]/Time'):
    #CODE NEEDED: to get dchannel to dynamically = channel[@name]
    ## Iterate over attributes of time for specific channel
    for attrib in df.attrib:
    dTime.append(df.attrib[attrib])
    ## value is a child of time, and iterate
    subfields = df.getchildren()
    for subfield in subfields:
    dvalue.append(subfield.text)
perf=DataFrame({'Channel': dchannel,'Time':dTime,'values':dvalue})

perf

Int64Index([], dtype=int64)
Empty DataFrame

如果我对所需的属性进行硬编码,例如for df in root.xpath('/*/*/*/channel[@name="blah"]/Time'):,它将为一个属性打印它,但我无法通过引用txt1[] 使其工作。

我尝试参考{0}..., txt1[],但随后它为 dchannel 属性吐出一个元组(因为它正在获取所有 txt1 而不是获取作为时间节点父级的 txt1 属性名称。

我查看了 XPath 文档,并且已经完成了 lxml 教程,但我无法弄清楚为什么我的动态搜索不起作用。我需要退回到.findall() 吗?如何使用此动态搜索来获取 txt1 中每个值的数据?

可能有一种更pythonic的方法来解决这个问题,例如设置一个函数,获取父级的属性[@name],子级的属性[@Time],然后是孙子的文本value,但我还没想好怎么做。

【问题讨论】:

    标签: python xpath lxml


    【解决方案1】:

    好的,我解决了这个问题 - 但解决方案仍然很难看。

    我很高兴能够得到我想要的输出。如果有人有更清洁的方法,我很乐意看到它。谢谢。

    dTime=[]
    dchannel = []
    dvalue=[]
    for df in root.xpath('//channel/Time'):
        dchannel.append(df.getparent().attrib['name'])
        ## Iterate over attributes of time for specific channel
        for attrib in df.attrib:
        dTime.append(df.attrib[attrib])
        ## value is a child of time, and iterate
        subfields = df.getchildren()
        for subfield in subfields:
        dvalue.append(subfield.text)
    perf=DataFrame({'Channel': dchannel,'Time':dTime,'values':dvalue})
    
    perf[:2]
       Channel     Time                    value
    0    blah        2013-05-01 00:00:00    258
    1    blah        2013-05-01 00:01:00    259
    2    blah        2013-05-01 00:02:00    258
    
    perf[12957:12960]
       Channel     Time                    value
    12957   lir      2013-05-01 00:00:00    67
    12958   lir      2013-05-01 00:01:00    67
    12959   lir      2013-05-01 00:02:00    66
    

    【讨论】:

      猜你喜欢
      • 2017-07-13
      • 1970-01-01
      • 1970-01-01
      • 2016-03-18
      • 1970-01-01
      • 2017-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多