Удалите специальные символы из ключей анализируемого XML-файла, используя xmltodict
Я проанализировал XML-файл, используя xmltodict
Модуль и результат хранятся в словаре словарей.
Теперь я хочу удалить специальные символы @
а также #
в каждом ключе словаря.
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("#")
3 ответа
Вы не должны удалять эти специальные символы из вашего ответа.
Есть вариант вообще не включать их в свой ответ.;-)
result = xmltodict.parse(response, attr_prefix='@', cdata_key='#text')
Это параметры по умолчанию, но вы можете установить attr_prefix=''
избавиться от @
символы и изменения cdata_key
таким же образом.
PS Кроме того, вы также можете использовать dict_constructor=dict
например, для создания словарей в разобранном ответе вместо OrderDicts, если вы не хотите конвертировать его обратно в XML с помощью xmltodict.unparse()
,
Удалять @
из ключей использования словаря attr_prefix=''
в качестве аргумента функции xmltodict.parse(). Удалять #
из ключей использования словаря cdata_key='text'
в качестве аргумента xmltodict.parse()
функция.
Текстовые значения для узлов могут быть указаны с помощью
cdata_key
введите python dict, а свойства узла можно указать с помощьюattr_prefix
с префиксом имени ключа в python dict. Значение по умолчанию дляattr_prefix
является@
и значение по умолчанию дляcdata_key
является#text
,
Нажмите здесь для подробностей.
Не существует прямого способа исключить их во время синтаксического анализа, поскольку они используются для обозначения атрибутов и текстовых узлов, позволяющих их отличать от элементов (если бы их не было, выходные данные были бы непригодны для использования).
Например
xmltodict.parse("""
<root>
<abc><def>ab</def></abc>
<abc id="a3">efg</abc>
</root>
""")
производит вложенный упорядоченный dict со структурой
{'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 на операторы типа print "Attribute: "+ky[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'}]}})