Редактировать XML как словарь в Python? - PullRequest
8 голосов
/ 24 сентября 2008

Я пытаюсь сгенерировать настроенные 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') 

Есть ли способ сделать это, или кто-то может предложить сделать это по-другому?

Ответы [ 8 ]

19 голосов
/ 21 февраля 2010

Это даст вам диктат минус атрибуты ... не знаю, если это будет полезно для кого-либо. Я искал 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!"}]}
11 голосов
/ 24 сентября 2008

Я не уверен, проще ли сначала преобразовать набор информации во вложенные dicts. Используя 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 .

8 голосов
/ 24 сентября 2008

Для удобства манипулирования XML в python мне нравится библиотека Beautiful Soup Это работает примерно так:

Пример 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>
4 голосов
/ 22 мая 2011

Моя модификация ответа Даниила, чтобы дать немного более точный словарь:

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

namespace - это строка 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>

слишком

есть возможность объединить словарь атрибутов / словарь вложенных тегов аналогично тому, как объединяются повторяющиеся вложенные теги, хотя вложение списков кажется уместным: -)

1 голос
/ 15 мая 2012

Добавление этой строки

d.update(('@' + k, v) for k, v in el.attrib.iteritems())

в коде user247686 вы также можете иметь атрибуты узла.

Нашел в этом посте 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)
0 голосов
/ 22 марта 2012

XML имеет богатый информационный набор, и для его представления в словаре Python требуются специальные приемы. Элементы упорядочены, атрибуты отличаются от тел элементов и т. Д.

Один проект для обработки циклов между словарями XML и Python с некоторыми вариантами конфигурации для обработки компромиссов по-разному - Поддержка XML в инструментах засолки . Требуется версия 1.3 и новее. Это не чистый Python (и фактически предназначен для облегчения взаимодействия C ++ / Python), но он может подходить для различных случаев использования.

0 голосов
/ 30 марта 2010

самый прямой путь ко мне:

root        = ET.parse(xh)
data        = root.getroot()
xdic        = {}
if data > None:
    for part in data.getchildren():
        xdic[part.tag] = part.text
0 голосов
/ 24 сентября 2008

Вы пробовали это?

print xml.etree.ElementTree.tostring( conf_new )
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...