#python-3.x #xml #xpath #elementtree
#python-3.x #xml #xpath #elementtree
Вопрос:
XML-файл, который я пытаюсь проанализировать, можно найти здесь . Этот XML имеет определенное пространство имен. Вот пример из XML-файла с элементами pertintnet:
<series>
<header>
<type>instantaneous</type>
<locationId>Fredericton</locationId>
<parameterId>HG</parameterId>
<timeStep unit="second" multiplier="3600"/>
<startDate date="2020-05-11" time="07:00:00"/>
<endDate date="2020-05-15" time="07:00:00"/>
<missVal>-999</missVal>
<stationName>SAINT JOHN RIVER AT FREDERICTON</stationName>
<units>M</units>
</header>
<event date="2020-05-11" time="07:00:00" value="4.69" flag="0"/>
<event date="2020-05-11" time="08:00:00" value="4.66" flag="0"/>
<event "many records deleted to save space"/>
<event date="2020-05-15" time="06:00:00" value="4.27" flag="0"/>
<event date="2020-05-15" time="07:00:00" value="-999" flag="8"/>
</series>
Мне нужно выполнить поиск в XML-файле по тексту, хранящемуся в <locationId>
элементах, например, «Fredericton». Как только я нахожу «Fredericton», мне нужно извлечь <parmeterId>
текст, а также получить атрибуты из первого и последнего <event>
элементов. Вот код, который у меня есть до сих пор. Как я могу использовать XPath для доступа к нужным мне элементам? Я прокомментировал свою попытку, которая не сработала.
import os
from xml.etree import ElementTree as ET
file_name = 'StJohn_FEWSNB_export.xml'
full_file = os.path.abspath(os.path.join('data', file_name))
print(full_file)
tree = ET.parse(full_file)
root = tree.getroot()
location_lst = [
'Nashwaak','Kennebecasis','Fredericton','Maugerville','Jemseg','Grand_Lake',
'Lakeville_Corner','Gagetown','Oak_Point','Hampton','Saint_John','Connors',
'St_Francois','Ft_Kent','Baker_Brook','St_Hilaire','Edmundston','Iroquois',
'St_Basile','St_Anne','St_Leonard','Perth','Simonds','Hartland','Woodstock'
]
for loc in location_lst:
for location in root.iter('{http://www.wldelft.nl/fews/PI}locationId'):
if location.text == loc:
## type = element.findall('.//{http://www.wldelft.nl/fews/PI}parameterId')
print(loc, location.text)
Спасибо,
Берни.
Ответ №1:
Вот ответ, использующий lxml вместо elementtree и упрощенные версии вашего xml и списка местоположений, чтобы извлечь уменьшенную версию вашего вывода. Очевидно, что вы можете изменить все это в соответствии с фактическим XML и выводом:
from lxml import etree
events = """<?xml version="1.0" encoding="UTF-8"?>
<root>
<series>
<header>
<type>instantaneous</type>
<locationId>Lakeville_Corner</locationId>
<parameterId>SSTG</parameterId>
<timeStep unit="second" multiplier="3600" />
</header>
<event date="2020-05-15" time="07:00:00" value="3.64" flag="0" />
<event date="2020-05-15" time="08:00:00" value="3.64" flag="0" />
<event date="2020-05-20" time="07:00:00" value="3.157" flag="0" />
</series>
<series>
<header>
<type>instantaneous</type>
<locationId>Gagetown</locationId>
<parameterId>HG</parameterId>
<timeStep unit="second" multiplier="3600" />
</header>
<event date="2020-05-11" time="07:00:00" value="3.99" flag="0" />
<event date="2020-05-11" time="08:00:00" value="3.99" flag="0" />
<event date="2020-05-15" time="07:00:00" value="3.43" flag="0" />
</series>
</root>
"""
doc = etree.XML(events.encode())
location_lst = ["Lakeville_Corner",'Gagetown']
series = doc.xpath('//series')
location_lst = ["Lakeville_Corner",'Gagetown']
series = doc.xpath('//series')
for loc in location_lst:
for s in series:
exp = f'./header/locationId[text()="{loc}"]'
target = s.xpath(exp)
if target:
pid = target[0].xpath('./following-sibling::parameterId/text()')[0]
date_first = s.xpath('.//event[1]/@date')[0]
value_first = s.xpath('.//event[1]/@value')[0]
date_last = s.xpath('.//event[last()]/@date')[0]
value_last = s.xpath('.//event[last()]/@value')[0]
print(loc,pid,date_first,value_first,date_last,value_last)
Вывод:
Lakeville_Corner SSTG 2020-05-15 3.64 2020-05-20 3.157
Gagetown HG 2020-05-11 3.99 2020-05-15 3.43