XML als Wörterbuch in Python zu bearbeiten?
-
02-07-2019 - |
Frage
Ich versuche, kundenspezifische XML-Dateien aus einer Vorlage XML-Datei in Python zu generieren.
Konzeptionell, möchte ich in der Vorlage xml lesen, einige Elemente entfernen, ändern einige Textattribute, und die neue XML in eine Datei zu schreiben. Ich wollte es so etwas wie dies funktioniert:
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)
Jetzt möchte ich eine Datei schreiben, aber ich sehe nicht, wie zu bekommen ElementTree.ElementTree.write ()
conf_new.write('config-new.xml')
Gibt es eine Möglichkeit, dies zu tun, oder kann jemand vorschlagen, dies eine andere Art und Weise zu tun?
Lösung
Für eine einfache Manipulation von XML in Python, wie ich die Schöne Suppe Bibliothek. Es funktioniert so etwas wie folgt aus:
Beispiel-XML-Datei:
<root>
<level1>leaf1</level1>
<level2>leaf2</level2>
</root>
Python-Code:
from BeautifulSoup import BeautifulStoneSoup, Tag, NavigableString
soup = BeautifulStoneSoup('config-template.xml') # get the parser for the xml file
soup.contents[0].name
# u'root'
Sie können die Knotennamen als Methoden verwenden:
soup.root.contents[0].name
# u'level1'
Es ist auch möglich, reguläre Ausdrücke zu verwenden:
import re
tags_starting_with_level = soup.findAll(re.compile('^level'))
for tag in tags_starting_with_level: print tag.name
# level1
# level2
Hinzufügen und Einfügen neuer Knoten ist ziemlich einfach:
# 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>
Andere Tipps
Dieses finden Sie eine dict bekommen minus Attribute ... weiß nicht, ob dies jedem nützlich ist. Ich war selbst für eine xml zu dict Lösung suchen, wenn ich mit dieser kam.
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
Das 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>
entspräche dies:
{'note': [{'to': 'Tove'},
{'from': 'Jani'},
{'heading': 'Reminder'},
{'body': "Don't forget me this weekend!"}]}
Ich bin mir nicht sicher, ob die Info-Umwandlung auf verschachtelte dicts ersten einfacher ist. Mit ElementTree, können Sie dies tun:
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 wurde so konzipiert, dass Sie müssen nicht Ihre XML-Bäume auf Listen konvertieren und Attribute zuerst, da es genau die intern verwendet.
Es unterstützt auch als kleine Untergruppe von XPath .
Meine Modifikation von Daniels Antwort, ein geringfügig ordentlicheres Wörterbuch geben:
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 ist die xmlns Zeichenfolge, einschließlich Klammern, dass ElementTree an alle Tags prepends, so hier habe ich klären, da es ein Namensraum für das gesamte Dokument ist
NB, dass ich die rohe XML zu so eingestellt, dass ‚leeren‘ Tags höchstens einem ‚‘ Text-Eigenschaft in der ElementTree Darstellung erzeugen würde
spacepattern = re.compile(r'\s+')
mydictionary = xml_to_dictionary(ElementTree.XML(spacepattern.sub(' ', content)))
würde zum Beispiel geben
{'note': {'to': 'Tove',
'from': 'Jani',
'heading': 'Reminder',
'body': "Don't forget me this weekend!"}}
es für bestimmten XML ausgelegt ist, die im Grunde äquivalent zu json, sollte Element behandeln Attribute wie
<elementName attributeName='attributeContent'>elementContent</elementName>
zu
gibt es die Möglichkeit einer Verschmelzung das Attribut Wörterbuch / Subtag Wörterbuch ähnlich wie wiederholen Subtags verschmolzen werden, obwohl Verschachtelung der Listen Art angemessen erscheint: -)
Das Hinzufügen dieser Zeile
d.update(('@' + k, v) for k, v in el.attrib.iteritems())
in der user247686 Code Knoten haben auch Attribute.
es in diesem Beitrag https://stackoverflow.com/a/7684581/1395962
Beispiel:
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
Anruf als
xml_to_dict(root)
Haben Sie versucht das?
print xml.etree.ElementTree.tostring( conf_new )
direkteste Weg zu mir:
root = ET.parse(xh)
data = root.getroot()
xdic = {}
if data > None:
for part in data.getchildren():
xdic[part.tag] = part.text
XML hat eine reiche infoset, und es dauert einige spezielle Tricks, dass in einem Python-Wörterbuch darzustellen. Elemente sind in der Reihenfolge, sind Attribute unterscheiden von Elementkörper, etc.
Ein Projekt Umläufe zwischen XML und Python Wörterbücher, mit einigen Konfigurationsoptionen zu handhaben die Vor- und Nachteile auf unterschiedliche Weise zu handhaben ist XML-Unterstützung in Abbeizen Werkzeuge . Version 1.3 und höher erforderlich. Es ist nicht reines Python (und in der Tat wird entwickelt, um C ++ / Python Interaktion einfacher zu machen), aber es könnte für verschiedene Anwendungsfälle geeignet sein.