使用有序字典解析xml文件

时间:2014-11-14 09:10:02

标签: python xml dictionary xml-parsing xmltodict

我有一个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 个答案:

答案 0 :(得分:5)

如果你以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"]

答案 1 :(得分:1)

您实际上可以通过设置其他关键字参数来避免转换为OrderedDict:

[]

obj = xmltodict.parse(xmldata, dict_constructor=dict) 将关键字参数转发给parse_DictSAXHandler默认设置为dict_constructor

答案 2 :(得分:0)

Mu的答案对我有用,我唯一需要改变的是棘手的确保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"]