繁体   English   中英

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

[英]Remove special characters from keys of a parsed xml file using 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("#")

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

有一个选项是根本不让它们出现在您的回复中。 ;-)

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

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

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

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

例如

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 语法,其中打印命令是一个函数。 要使此示例在 python 2.6 或 2.7 中工作,首先发出from __future__ import print_function或将打印函数调用更改为类似print "Attribute: "+ky[1:]语句。

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

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

单击此处了解详细信息。

发生这种情况是因为您的功能没有“深入”。 因此,让我们从@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'}]}}

您的函数将在此 dict 中仅找到一个键: 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'}]}})

import xmltodict result = xmltodict.parse(xml, attr_prefix="")将所有@替换为空字符串

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM