2008-09-24 32 views
8

Tôi đang cố tạo các tệp xml tùy chỉnh từ tệp xml mẫu trong python.Chỉnh sửa XML làm từ điển trong python?

Về mặt khái niệm, tôi muốn đọc trong mẫu xml, xóa một số thành phần, thay đổi một số thuộc tính văn bản và viết xml mới ra tệp. Tôi muốn nó hoạt động một cái gì đó như thế này:

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) 

bây giờ tôi muốn ghi vào tập tin, nhưng tôi không thấy làm thế nào để có được để ElementTree.ElementTree.write()

conf_new.write('config-new.xml') 

Is có một số cách để làm điều này, hoặc ai đó có thể đề nghị làm điều này một cách khác nhau?

Trả lời

8

Để dễ dàng thao tác XML trong python, tôi thích thư viện Beautiful Soup. Nó hoạt động một cái gì đó như thế này:

mẫu XML File:

đang
<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' 

Bạn có thể sử dụng các tên nút như các phương pháp:

soup.root.contents[0].name 
# u'level1' 

Đây cũng là có thể sử dụng regexes:

import re 
tags_starting_with_level = soup.findAll(re.compile('^level')) 
for tag in tags_starting_with_level: print tag.name 
# level1 
# level2 

Thêm và chèn node mới khá đơn giản:

# 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 chuyển đổi mọi thứ thành thấp hơn. Điều đó thật sự rất tệ. Tôi phải bảo tồn các trường hợp thẻ và giá trị! – user236215

+0

Tác giả của BeautifulSoup nói rằng điều này thực hiện điều này bởi vì HTMLParser làm điều đó. "Nếu bạn cần bảo quản thẻ, hãy thử lxml". – nealmcb

11

Tôi không chắc chắn liệu việc chuyển đổi tập thông tin thành các đoạn mã lồng nhau có dễ dàng hơn không. Sử dụng ElementTree, bạn có thể làm điều này:

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 được thiết kế để bạn không cần phải chuyển đổi cây XML của bạn vào các danh sách và các thuộc tính đầu tiên, vì nó sử dụng một cách chính xác rằng trong nội bộ.

Nó cũng hỗ trợ dưới dạng tập con nhỏ XPath.

+1

Cũng có thể chỉ cần sử dụng 'find' mục 'phân lvl1', chứ không phải là 'findall' và lấy phần tử đầu tiên. –

0

Bạn đã thử cái này chưa?

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

này sẽ giúp bạn có một dict trừ thuộc tính ... dunno nếu điều này rất hữu ích cho bất cứ ai. Tôi đã tìm kiếm một giải pháp xml để dict bản thân mình khi tôi đến với điều này.



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 

này: 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> 

có bằng này:


{'note': [{'to': 'Tove'}, 
      {'from': 'Jani'}, 
      {'heading': 'Reminder'}, 
      {'body': "Don't forget me this weekend!"}]} 
+0

rất hữu ích cho tôi; cảm ơn! – mellort

+0

Đây chính xác là những gì tôi đang tìm kiếm. Và sử dụng 'map' nhận điểm thưởng cho tôi. Làm tốt. –

0

cách trực tiếp nhất đối với tôi:

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

sửa đổi của tôi về câu trả lời của Daniel, để đưa ra một marginall y gọn gàng từ điển:

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 là chuỗi xmlns, bao gồm niềng răng, rằng ElementTree prepends để tất cả các thẻ, vì vậy ở đây tôi đã xóa nó như có một không gian tên cho toàn bộ tài liệu

NB mà tôi điều chỉnh xml thô quá, do đó 'rỗng' thẻ sẽ tạo ra tối đa là một '' tài sản văn bản trong các đại diện ElementTree

spacepattern = re.compile(r'\s+') 
mydictionary = xml_to_dictionary(ElementTree.XML(spacepattern.sub(' ', content))) 

sẽ cung cấp cho ví dụ

{'note': {'to': 'Tove', 
     'from': 'Jani', 
     'heading': 'Reminder', 
     'body': "Don't forget me this weekend!"}} 

nó được thiết kế cho xml cụ thể mà về cơ bản là tương đương với json, nên xử lý yếu tố thuộc tính như

<elementName attributeName='attributeContent'>elementContent</elementName> 

quá

có khả năng sáp nhập các từ điển thuộc tính/thẻ phụ điển tương tự như thẻ phụ như thế nào lặp lại được hợp nhất, mặc dù lồng các danh sách có vẻ thích hợp :-)

0

XML có một tệp thông tin phong phú và cần một số thủ thuật đặc biệt để thể hiện trong từ điển Python. Các phần tử được sắp xếp, các thuộc tính được phân biệt với các phần tử phần tử, vv

Một dự án để xử lý các chuyến đi khứ hồi giữa từ điển XML và Python, với một số tùy chọn cấu hình để xử lý sự cân bằng theo các cách khác nhau là XML Support in Pickling Tools. Phiên bản 1.3 và mới hơn là bắt buộc. Nó không phải là Python thuần túy (và trên thực tế được thiết kế để làm cho tương tác C++/Python dễ dàng hơn), nhưng nó có thể thích hợp cho các trường hợp sử dụng khác nhau.

1

Thêm dòng

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

này trong user247686's code bạn có thể có nút thuộc tính quá.

Tìm thấy nó trong bài này https://stackoverflow.com/a/7684581/1395962

Ví dụ:

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 

Gọi như

xml_to_dict(root) 
Các vấn đề liên quan