Question

J'essaie de générer des fichiers XML personnalisés à partir d'un fichier XML modèle en python.

Sur le plan conceptuel, je souhaite lire le modèle XML, supprimer certains éléments, modifier certains attributs de texte et écrire le nouveau XML dans un fichier. Je voulais que ça marche quelque chose comme ça:

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)

maintenant je veux écrire dans un fichier, mais je ne vois pas comment arriver à ElementTree.ElementTree.write ()

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

Y a-t-il un moyen de faire cela, ou quelqu'un peut-il suggérer de le faire d'une manière différente?

Était-ce utile?

La solution

Pour une manipulation aisée de XML en python, j'aime bien la bibliothèque Beautiful Soup . Cela fonctionne à peu près comme ceci:

Exemple de fichier XML:

<root>
  <level1>leaf1</level1>
  <level2>leaf2</level2>
</root>

Code 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'

Vous pouvez utiliser les noms de nœud comme méthodes:

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

Il est également possible d'utiliser des expressions rationnelles:

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

Ajouter et insérer de nouveaux nœuds est assez simple:

# 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>

Autres conseils

Cela vous donnera un dict moins les attributs ... je ne sais pas si cela peut vous être utile. Je cherchais un xml pour dicter la solution moi-même quand je suis arrivé à cela.



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

This: 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>

serait égal à ceci:


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

Je ne sais pas s'il est plus facile de convertir les informations en fichiers imbriqués en premier. En utilisant ElementTree, vous pouvez faire ceci:

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 a été conçu pour que vous n'ayez pas à convertir d'abord vos arbres XML en listes et en attributs, car il utilise exactement cela en interne.

Il prend également en charge un sous-ensemble de XPath .

Ma modification de la réponse de Daniel, pour donner un dictionnaire un peu plus ordonné:

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 est la chaîne xmlns, y compris les accolades, qu'ElementTree ajoute à toutes les balises. Je l'ai donc effacée, car il n'y a qu'un seul espace de nommage pour l'ensemble du document

Notez que j'ai également ajusté le code XML brut, de sorte que les balises 'vides' produisent au plus une propriété de texte '' dans la représentation ElementTree

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

donnerait par exemple

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

il est conçu pour un xml spécifique qui est fondamentalement équivalent à json, devrait gérer des attributs d'élément tels que

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

aussi

il est possible de fusionner le dictionnaire d'attributs / dictionnaire de sous-étiquettes de la même manière que le mode de fusion des sous-étiquettes de répétition, bien que l'imbrication des listes semble un peu appropriée: -)

Ajout de cette ligne

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

dans le code de l'utilisateur 247686 , vous pouvez également avoir des attributs de nœud.

trouvé dans cet article https://stackoverflow.com/a/7684581/1395962

Exemple:

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

Appeler en tant que

xml_to_dict(root)

Avez-vous essayé cela?

print xml.etree.ElementTree.tostring( conf_new )

moyen le plus direct pour moi:

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

XML a un riche ensemble d’informations, et des astuces spéciales sont nécessaires pour le représenter dans un dictionnaire Python. Les éléments sont ordonnés, les attributs sont distingués des corps d’éléments, etc.

Prise en charge de XML dans les outils de décapage . La version 1.3 et plus récente est requise. Ce n’est pas du pur Python (et est en fait conçu pour faciliter l’interaction C ++ / Python), mais cela pourrait convenir à divers cas d’utilisation.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top