Разбор XML-файла с упорядоченным словарем
У меня есть xml
файл формы:
<NewDataSet>
<Root>
<Phonemic>and</Phonemic>
<Phonetic>nd</Phonetic>
<Description/>
<Start>0</Start>
<End>8262</End>
</Root>
<Root>
<Phonemic>comfortable</Phonemic>
<Phonetic>comfetebl</Phonetic>
<Description>adj</Description>
<Start>61404</Start>
<End>72624</End>
</Root>
</NewDataSet>
Мне нужно обработать его так, чтобы, например, когда пользователь вводит nd
программа сопоставляет его с <Phonetic>
тег и возврат and
от <Phonemic>
часть. Я подумал, может быть, если я смогу преобразовать XML-файл в словарь, я смог бы перебирать данные и находить информацию, когда это необходимо.
Я искал и нашел xmltodict, который используется для той же цели:
import xmltodict
with open(r'path\to\1.xml', encoding='utf-8', errors='ignore') as fd:
obj = xmltodict.parse(fd.read())
Запуск это дает мне ordered dict
:
>>> obj
OrderedDict([('NewDataSet', OrderedDict([('Root', [OrderedDict([('Phonemic', 'and'), ('Phonetic', 'nd'), ('Description', None), ('Start', '0'), ('End', '8262')]), OrderedDict([('Phonemic', 'comfortable'), ('Phonetic', 'comfetebl'), ('Description', 'adj'), ('Start', '61404'), ('End', '72624')])])]))])
Теперь это, к сожалению, не упростило ситуацию, и я не уверен, как реализовать программу с новой структурой данных. Например для доступа nd
Я должен написать:
obj['NewDataSet']['Root'][0]['Phonetic']
что смешно сложно. Я пытался превратить его в обычный словарь dict()
но так как он вложенный, внутренние слои остаются упорядоченными, а мои данные такими большими.
3 ответа
Если вы получаете доступ к этому как obj['NewDataSet']['Root'][0]['Phonetic']
IMO, вы не делаете это правильно.
Вместо этого вы можете сделать следующее
obj = obj["NewDataSet"]
root_elements = obj["Root"] if type(obj) == OrderedDict else [obj["Root"]]
# Above step ensures that root_elements is always a list
for element in root_elements:
print element["Phonetic"]
Хотя этот код выглядит намного длиннее, его преимущество в том, что он станет намного более компактным и модульным, как только вы начнете работать с достаточно большим XML-файлом.
PS: у меня были те же проблемы с xmltodict
, Но вместо синтаксического анализа с использованием xml.etree.ElementTree для синтаксического анализа файлов xml работать с xmltodict было намного проще, так как базовая часть кода была меньше, и мне не приходилось иметь дело с другими объектами модуля xml.
РЕДАКТИРОВАТЬ
Следующий код работает для меня
import xmltodict
from collections import OrderedDict
xmldata = """<NewDataSet>
<Root>
<Phonemic>and</Phonemic>
<Phonetic>nd</Phonetic>
<Description/>
<Start>0</Start>
<End>8262</End>
</Root>
<Root>
<Phonemic>comfortable</Phonemic>
<Phonetic>comfetebl</Phonetic>
<Description>adj</Description>
<Start>61404</Start>
<End>72624</End>
</Root>
</NewDataSet>"""
obj = xmltodict.parse(xmldata)
obj = obj["NewDataSet"]
root_elements = obj["Root"] if type(obj) == OrderedDict else [obj["Root"]]
# Above step ensures that root_elements is always a list
for element in root_elements:
print element["Phonetic"]
Вы можете избежать преобразования в OrderedDict, установив дополнительный параметр ключевого слова:
obj = xmltodict.parse(xmldata, dict_constructor=dict)
parse
пересылает аргументы ключевых слов _DictSAXHandler
а также dict_constructor
по умолчанию установлено OrderedDict
,
Ответ Му работал для меня, единственное, что я должен был изменить, это хитрый способ убедиться, что root_element всегда является шагом списка.
import xmltodict
from collections import OrderedDict
xmldata = """<NewDataSet>
<Root>
<Phonemic>and</Phonemic>
<Phonetic>nd</Phonetic>
<Description/>
<Start>0</Start>
<End>8262</End>
</Root>
<Root>
<Phonemic>comfortable</Phonemic>
<Phonetic>comfetebl</Phonetic>
<Description>adj</Description>
<Start>61404</Start>
<End>72624</End>
</Root>
</NewDataSet>"""
obj = xmltodict.parse(xmldata)
obj = obj["NewDataSet"]
root_elements = obj["Root"] if type(obj["Root"]) == list else [obj["Root"]]
# Above step ensures that root_elements is always a list
# Is obj["Root"] a list already, then use obj["Root"], otherwise make single element list.
for element in root_elements:
print element["Phonetic"]