2013-06-05 2 views
0

Я работаю над перемещением соседних xml-данных в иерархический фрейм данных. Я смог получить все данные из xml благодаря помощи в SO. Однако теперь я работаю над очисткой данных, которые я извлекаю и формирую их перед выходом, потому что я буду делать это тысячи раз.Динамический поиск по атрибутам xml с использованием lxml и xpath в python

ОБНОВЛЕНО: ЭТО, ЧТО Я ВЕЧЕР ВСТРЕЧА. Кажется, я не могу получить только Time и value для channel динамически. Имена каналов будут изменены для каждого файла.

Когда 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 и решил проблему получения значений time и value в кадре данных: 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 имя, которое является родителем времени узла атрибута.

I просмотрел документацию XPath, и я прошел через учебник lxml, и я не могу понять, почему мой динамический поиск не работает. Мне нужно вернуться к .findall()? Как я могу использовать этот динамический поиск для получения данных для каждого значение в txt1?

Возможно, существует более питонический подход к этому, например, создание функции, которая получает attr ibute [@name] родителя, атрибут [@Time] ребенка, а затем текст внука value, но я еще не понял, как это сделать.

ответ

0

Хорошо, я решил это, но решение по-прежнему некрасиво.

Я рад, что понял, что хочу получить результат, который я хочу.Если у кого-то есть более чистый метод, я бы ЛЮБЛЮ, чтобы это увидеть. Благодарю.

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 

YAY

Смежные вопросы