2008-09-24 3 views
8

Я пытаюсь создать настроенные XML-файлы из XML-файла шаблона в python.Редактирование 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') 

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

ответ

8

Для облегчения манипуляций с 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> 
+3

BeautifulSoup преобразует все в нижний регистр. Это действительно отстой. Я должен сохранять случаи тегов и ценностей! – user236215 2010-05-19 21:13:51

+0

Автор BeautifulSoup говорит, что он делает это, потому что это делает HTMLParser. «Если вам нужно сохранить тег тега, попробуйте lxml». – nealmcb 2012-03-21 18:14:35

11

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

+1

Мог бы также просто использовать `find` на` lvl1` задания, а не `findall` и получить первый элемент. – 2011-09-03 02:46:46

0

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

print xml.etree.ElementTree.tostring(conf_new) 
19

Это будет получить вам 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!"}]} 
0

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

root  = ET.parse(xh) 
data  = root.getroot() 
xdic  = {} 
if data > None: 
    for part in data.getchildren(): 
     xdic[part.tag] = part.text 
4

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

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> 

слишком

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

0

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

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

1

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

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

в user247686's code вы можете иметь узел атрибутов тоже.

Найдено его на этом посту 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) 
Смежные вопросы