Анализ XML в Python с использованием примера ElementTree
-
21-09-2019 - |
Вопрос
Мне трудно найти хороший базовый пример того, как анализировать XML в Python с использованием дерева элементов.Насколько мне удалось найти, это самая простая библиотека для анализа XML.Вот образец XML, с которым я работаю:
<timeSeriesResponse>
<queryInfo>
<locationParam>01474500</locationParam>
<variableParam>99988</variableParam>
<timeParam>
<beginDateTime>2009-09-24T15:15:55.271</beginDateTime>
<endDateTime>2009-11-23T15:15:55.271</endDateTime>
</timeParam>
</queryInfo>
<timeSeries name="NWIS Time Series Instantaneous Values">
<values count="2876">
<value dateTime="2009-09-24T15:30:00.000-04:00" qualifiers="P">550</value>
<value dateTime="2009-09-24T16:00:00.000-04:00" qualifiers="P">419</value>
<value dateTime="2009-09-24T16:30:00.000-04:00" qualifiers="P">370</value>
.....
</values>
</timeSeries>
</timeSeriesResponse>
Я могу делать то, что мне нужно, используя жестко запрограммированный метод.Но мне нужно, чтобы мой код был немного более динамичным.Вот что сработало:
tree = ET.parse(sample.xml)
doc = tree.getroot()
timeseries = doc[1]
values = timeseries[2]
print child.attrib['dateTime'], child.text
#prints 2009-09-24T15:30:00.000-04:00, 550
Вот несколько вещей, которые я пробовал, ни одна из них не сработала, сообщая, что они не смогли найти timeSeries (или что-нибудь еще, что я пробовал):
tree = ET.parse(sample.xml)
tree.find('timeSeries')
tree = ET.parse(sample.xml)
doc = tree.getroot()
doc.find('timeSeries')
По сути, я хочу загрузить файл xml, найти тег timeSeries и перебрать теги значений, возвращая дату и время и значение самого тега;все, что я делаю в приведенном выше примере, но не жестко кодирую интересующие меня разделы XML.Может ли кто-нибудь указать мне на несколько примеров или дать мне несколько советов о том, как с этим справиться?
Спасибо за помощь.Использование обоих приведенных ниже предложений сработало для предоставленного мной примера файла, однако они не сработали для полного файла.Вот ошибка, которую я получаю из реального файла, когда использую метод Эда Каррела:
(<type 'exceptions.AttributeError'>, AttributeError("'NoneType' object has no attribute 'attrib'",), <traceback object at 0x011EFB70>)
Я решил, что в реальном файле есть что-то, что ему не понравилось, поэтому постепенно удалял все, пока все не заработало.Вот строки, которые я изменил:
originally: <timeSeriesResponse xsi:schemaLocation="a URL I removed" xmlns="a URL I removed" xmlns:xsi="a URL I removed">
changed to: <timeSeriesResponse>
originally: <sourceInfo xsi:type="SiteInfoType">
changed to: <sourceInfo>
originally: <geogLocation xsi:type="LatLonPointType" srs="EPSG:4326">
changed to: <geogLocation>
Удаление атрибутов с «xsi:...» устранило проблему.Является ли «xsi:...» недействительным XML?Мне будет сложно удалить их программно.Любые предлагаемые обходные пути?
Вот полный XML-файл: http://www.sendspace.com/file/lofcpt
Когда я изначально задал этот вопрос, я не знал о пространствах имен в XML.Теперь, когда я знаю, что происходит, мне не нужно удалять атрибуты «xsi», которые являются объявлениями пространства имен.Я просто включаю их в поиск по xpath.Видеть эта страница для получения дополнительной информации о пространствах имен в lxml.
Решение
Итак, теперь у меня на компьютере установлена ElementTree 1.2.6, и я запустил следующий код для опубликованного вами фрагмента XML:
import elementtree.ElementTree as ET
tree = ET.parse("test.xml")
doc = tree.getroot()
thingy = doc.find('timeSeries')
print thingy.attrib
и получил обратно следующее:
{'name': 'NWIS Time Series Instantaneous Values'}
Похоже, он нашел элемент timeSeries без необходимости использования числовых индексов.
Теперь, что будет полезно, так это знать, что вы имеете в виду, когда говорите: «Это не работает». Поскольку это работает для меня, учитывая тот же ввод, маловероятно, что ElementTree разбит каким -то очевидным способом.Обновите свой вопрос, указав любые сообщения об ошибках, обратные трассировки или что-либо еще, что вы можете предоставить, чтобы помочь нам помочь вам.
Другие советы
Если я правильно понял ваш вопрос:
for elem in doc.findall('timeSeries/values/value'):
print elem.get('dateTime'), elem.text
или, если вы предпочитаете (и если есть только один случай timeSeries/values
:
values = doc.find('timeSeries/values')
for value in values:
print value.get('dateTime'), elem.text
А findall()
метод возвращает список всех совпадающих элементов, тогда как find()
возвращает только первый соответствующий элемент.Первый пример перебирает все найденные элементы, второй — дочерние элементы. values
элемент, что в данном случае приводит к тому же результату.
не вижу в чем проблема не найти timeSeries
происходит однако.Может быть, вы просто забыли getroot()
вызов?(обратите внимание, что на самом деле вам это не нужно, потому что вы также можете работать с самим элементомtree, если вы измените выражение пути, например, на /timeSeriesResponse/timeSeries/values
или //timeSeries/values
)