Разбор 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"]
Другие вопросы по тегам