使用xmltodict从解析的xml文件的键中删除特殊字符

时间:2016-02-17 09:26:20

标签: python xml xml-parsing xmltodict

我使用xmltodict模块解析了一个xml文件,结果存储在字典词典中。

现在我要删除字典中每个键中的特殊字符@#

def remove_using_json(parse_result):
    data = {}
    data = json.dumps(parse_result)
    #print data
    #for d in data:
    for key, value in data.iterkeys():
        if key[0] == '@':
            data[key]=key.strip("@")
        elif key[0] == '#':
            data[key] =key.strip("#")

4 个答案:

答案 0 :(得分:5)

您不应该从回复中删除这些特殊字符。

可以选择不让它们进入您的回复。 ; - )

result = xmltodict.parse(response, attr_prefix='@', cdata_key='#text')

这些是默认选项,但您可以设置attr_prefix=''以删除@符号,并以相同方式更改cdata_key

P.S。此外,您还可以使用dict_constructor=dict在已解析的响应中创建字典而不是OrderDicts,例如,如果您不能使用xmltodict.unparse()将其转换回XML。

答案 1 :(得分:2)

在解析过程中没有直接的方法来消除它们,因为它们用于表示属性和文本节点,允许它们与元素区分开(如果它们不存在输出将无法使用)。

例如

xmltodict.parse("""
    <root>
        <abc><def>ab</def></abc>
        <abc id="a3">efg</abc>
    </root>
""")

生成一个带有结构

的嵌套有序字典
{'root': {'abc': [ 
                     {'def': 'ab'},
                     {'@id': 'a3', '#text': 'efg'}
                 ]
         }
}

@ 符号告诉我 @id 是一个属性。如果没有该符号,我无法判断它是属性还是名为 id 的元素。同样,符号告诉我 #text 是该元素的文本值。没有它,我无法判断它是否是元素的文本,或者它是否是名为 text 的元素。

但是,在处理密钥时,您可以使用ky[1:]删除密钥,其中ky是密钥。

例如,如果我将上面解析的输出分配给变量doc,我可以做 1

for abcelem in doc["root"]["abc"]:
    for ky in abcelem:
        if ky[0]=="@": print("Attribute:",ky[1:])
        elif ky[0]=="#": print("Text Content")
        else: print("Element:",ky)

哪个会输出

Element: def
Attribute: id
Text Content

我从属性中删除了 @ 符号。

<小时/> 如果你真的想要从解析的值中完全删除这些符号,你可以编写一个递归函数来执行此操作。

def remover(x):
    if isinstance(x,list): return [remover(y) for y in x]
    elif isinstance(x,OrderedDict):
        for ky in list(x.keys()):
            if ky[0] in ["@","#"]: 
                x[ky[1:]] = remover(x[ky])
                del x[ky]
            else: x[ky] = remover(x[ky])
        return x
    else: return x

因此,在上文中,remover(doc)会从键中删除所有 @ 符号。行为可能不稳定,如果任何节点具有相同名称的元素和属性或名为 text 的元素或属性,则会丢失一些数据,这正是为什么这些符号首先出现在那里的原因。此函数确实修改了对象,因此,如果需要保留原始对象,则应进行深度复制并将其传递给函数。

<小时/> 1 这使用python 3语法,其中print命令是一个函数。要使此示例在python 2.6或2.7中工作,请首先发出from __future__ import print_function或将打印函数调用更改为print "Attribute: "+ky[1:]之类的语句。

答案 2 :(得分:1)

之所以发生这种情况,是因为您的功能无法深入了解。因此,让我们从@Matthew的答案中获取样本字典,例如:

d = xmltodict.parse("""
    <root>
        <abc><def>ab</def></abc>
        <abc id="a3">efg</abc>
    </root>
""")

In [29]: d
Out[29]: {'root': {'abc': [{'def': 'ab'}, {'#text': 'efg', '@id': 'a3'}]}}

您的函数只会在此词典中找到一个键:root。但是你可以用这样的方式递归迭代所有项目:

# What if you use different from dict Mapping implementation
# ...like OrderedDict or defaultdict? So lets check type 
# ...of the nested 'dicts' with Mapping interface
from collections import Mapping

def transform(element, strip_chars="#@"):
    if isinstance(element, Mapping):
        return {key.strip(strip_chars): transform(value) 
                    for key, value 
                    in element.iteritems()}
    elif isinstance(element, list):
        return [transform(item) for item in element]
    else:
        return element

In [27]: d1 = transform(d)

In [28]: d, d1
Out[28]: 
({'root': {'abc': [{'def': 'ab'}, {'#text': 'efg', '@id': 'a3'}]}},
 {'root': {'abc': [{'def': 'ab'}, {'id': 'a3', 'text': 'efg'}]}})

答案 3 :(得分:0)

要从字典键中删除@,请使用attr_prefix=''作为xmltodict.parse()函数的参数。 要从字典键中删除#,请使用cdata_key='text'作为xmltodict.parse()函数的参数。

  

节点的文本值可以使用python dict中的cdata_key键指定,而节点属性可以使用python dict中的键名前缀attr_prefix来指定。 attr_prefix的默认值为@cdata_key的默认值为#text

单击here了解详情。