Редактирование XML как словаря в Python?
-
02-07-2019 - |
Вопрос
Я пытаюсь создать индивидуальные XML-файлы из XML-файла шаблона в Python.
Концептуально я хочу прочитать XML-файл шаблона, удалить некоторые элементы, изменить некоторые текстовые атрибуты и записать новый XML-файл в файл.Я хотел, чтобы это работало примерно так:
conf_base = ConvertXmlToDict('config-template.xml')
conf_base_dict = conf_base.UnWrap()
del conf_base_dict['root-name']['level1-name']['leaf1']
del conf_base_dict['root-name']['level1-name']['leaf2']
conf_new = ConvertDictToXml(conf_base_dict)
Теперь я хочу написать в файл, но я не вижу, как добраться до elementtree.elementtree.write ()
conf_new.write('config-new.xml')
Есть ли какой-нибудь способ сделать это или может кто-то предложит сделать это по-другому?
Решение
Для простоты манипулирования XML в Python мне нравится Красивый суп библиотека.Это работает примерно так:
Пример XML-файла:
<root>
<level1>leaf1</level1>
<level2>leaf2</level2>
</root>
Код Python:
from BeautifulSoup import BeautifulStoneSoup, Tag, NavigableString
soup = BeautifulStoneSoup('config-template.xml') # get the parser for the xml file
soup.contents[0].name
# u'root'
Вы можете использовать имена узлов в качестве методов:
soup.root.contents[0].name
# u'level1'
Также можно использовать регулярные выражения:
import re
tags_starting_with_level = soup.findAll(re.compile('^level'))
for tag in tags_starting_with_level: print tag.name
# level1
# level2
Добавить и вставить новые узлы довольно просто:
# build and insert a new level with a new leaf
level3 = Tag(soup, 'level3')
level3.insert(0, NavigableString('leaf3')
soup.root.insert(2, level3)
print soup.prettify()
# <root>
# <level1>
# leaf1
# </level1>
# <level2>
# leaf2
# </level2>
# <level3>
# leaf3
# </level3>
# </root>
Другие советы
Это даст вам dict минус атрибуты...не знаю, пригодится ли это кому-нибудь.Я сам искал XML-файл, чтобы продиктовать решение, когда придумал это.
import xml.etree.ElementTree as etree
tree = etree.parse('test.xml')
root = tree.getroot()
def xml_to_dict(el):
d={}
if el.text:
d[el.tag] = el.text
else:
d[el.tag] = {}
children = el.getchildren()
if children:
d[el.tag] = map(xml_to_dict, children)
return d
Этот: http://www.w3schools.com/XML/note.xml
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
Будет равно этому:
{'note': [{'to': 'Tove'},
{'from': 'Jani'},
{'heading': 'Reminder'},
{'body': "Don't forget me this weekend!"}]}
Я не уверен, что сначала преобразовать набор информации во вложенные словари проще.Используя ElementTree, вы можете сделать это:
import xml.etree.ElementTree as ET
doc = ET.parse("template.xml")
lvl1 = doc.findall("level1-name")[0]
lvl1.remove(lvl1.find("leaf1")
lvl1.remove(lvl1.find("leaf2")
# or use del lvl1[idx]
doc.write("config-new.xml")
ElementTree был разработан таким образом, что вам не нужно сначала преобразовывать деревья XML в списки и атрибуты, поскольку он использует именно это внутри себя.
Он также поддерживает небольшое подмножество XPath.
Моя модификация ответа Дэниела, чтобы дать немного более аккуратный словарь:
def xml_to_dictionary(element):
l = len(namespace)
dictionary={}
tag = element.tag[l:]
if element.text:
if (element.text == ' '):
dictionary[tag] = {}
else:
dictionary[tag] = element.text
children = element.getchildren()
if children:
subdictionary = {}
for child in children:
for k,v in xml_to_dictionary(child).items():
if k in subdictionary:
if ( isinstance(subdictionary[k], list)):
subdictionary[k].append(v)
else:
subdictionary[k] = [subdictionary[k], v]
else:
subdictionary[k] = v
if (dictionary[tag] == {}):
dictionary[tag] = subdictionary
else:
dictionary[tag] = [dictionary[tag], subdictionary]
if element.attrib:
attribs = {}
for k,v in element.attrib.items():
attribs[k] = v
if (dictionary[tag] == {}):
dictionary[tag] = attribs
else:
dictionary[tag] = [dictionary[tag], attribs]
return dictionary
пространство имен — это строка xmlns, включая фигурные скобки, которую ElementTree добавляет ко всем тегам, поэтому здесь я очистил ее, поскольку для всего документа существует одно пространство имен.
Обратите внимание, что я также скорректировал необработанный XML, чтобы «пустые» теги создавали не более текстового свойства в представлении ElementTree.
spacepattern = re.compile(r'\s+')
mydictionary = xml_to_dictionary(ElementTree.XML(spacepattern.sub(' ', content)))
дал бы, например
{'note': {'to': 'Tove',
'from': 'Jani',
'heading': 'Reminder',
'body': "Don't forget me this weekend!"}}
он разработан для конкретного XML, который в основном эквивалентен json, должен обрабатывать атрибуты элемента, такие как
<elementName attributeName='attributeContent'>elementContent</elementName>
слишком
существует возможность объединения словаря атрибутов/словаря вложенных тегов аналогично тому, как объединяются повторяющиеся вложенные теги, хотя вложение списков кажется уместным :-)
Добавление этой строки
d.update(('@' + k, v) for k, v in el.attrib.iteritems())
в код пользователя247686 вы также можете иметь атрибуты узла.
Нашел это в этом посте https://stackoverflow.com/a/7684581/1395962
Пример:
import xml.etree.ElementTree as etree
from urllib import urlopen
xml_file = "http://your_xml_url"
tree = etree.parse(urlopen(xml_file))
root = tree.getroot()
def xml_to_dict(el):
d={}
if el.text:
d[el.tag] = el.text
else:
d[el.tag] = {}
children = el.getchildren()
if children:
d[el.tag] = map(xml_to_dict, children)
d.update(('@' + k, v) for k, v in el.attrib.iteritems())
return d
Позвонить как
xml_to_dict(root)
Вы пробовали это?
print xml.etree.ElementTree.tostring( conf_new )
самый прямой путь ко мне:
root = ET.parse(xh)
data = root.getroot()
xdic = {}
if data > None:
for part in data.getchildren():
xdic[part.tag] = part.text
XML имеет богатый информационный набор, и для его представления в словаре Python требуются специальные приемы.Элементы упорядочены, атрибуты отличаются от тел элементов и т. д.
Один проект для обработки двустороннего обмена между словарями XML и Python с некоторыми параметрами конфигурации для различных способов решения компромиссных решений: Поддержка XML в инструментах травления.Требуется версия 1.3 и новее.Это не чистый Python (и фактически он предназначен для упрощения взаимодействия C++/Python), но он может подойти для различных случаев использования.