Pergunta

Eu estou tentando gerar arquivos XML personalizado de um arquivo de modelo xml em python.

Conceitualmente, eu quero ler no xml modelo, remover alguns elementos, alterar alguns atributos de texto, e escrever o novo xml em um arquivo. Eu queria que o trabalho algo como isto:

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)

Agora eu quero escrever para o arquivo, mas não vejo como chegar a ElementTree.ElementTree.write ()

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

Existe alguma maneira de fazer isso, ou alguém pode sugerir fazendo isso de forma diferente?

Foi útil?

Solução

Para facilitar a manipulação de XML em python, eu como a biblioteca Soup bonito. Ele funciona assim:

Exemplo de arquivo XML:

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

código 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'

Você pode usar os nomes de nó como métodos:

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

Também é possível regexes uso:

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

Adicionando e inserir novos nós é bastante simples:

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

Outras dicas

Isso vai levá-lo um dicionário atributos menos ... não sei se isso é útil para qualquer pessoa. Eu estava procurando por um xml para solução dict mim quando eu vim com isso.



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

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

seria igual a este:


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

Eu não tenho certeza se convertendo a informação pronto para dicts aninhados primeiro é mais fácil. Usando ElementTree, você pode fazer isso:

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 foi projetado de modo que você não tem que converter seus árvores XML para listas e atributos primeiro, uma vez que utiliza exatamente isso internamente.

Ele também suporta tão pequeno subconjunto de XPath .

Meu modificação da resposta de Daniel, para dar uma marginalmente mais puro dicionário:

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 é a string xmlns, incluindo chaves, que ElementTree prepends a todas as tags, então aqui eu já limpou-o como há um namespace para todo o documento

NB que eu ajustei o XML bruto também, para que as tags 'vazio' iria produzir, no máximo, uma '' propriedade de texto na representação ElementTree

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

daria por exemplo

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

é projetado para xml específico que é basicamente equivalente a JSON, deve lidar com elemento atributos como

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

muito

existe a possibilidade de fundir o atributo dicionário / subtag dicionário da mesma forma como subtags repetição são mesclados, embora nidificação das listas parece meio apropriado: -)

Adicionando esta linha

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

no código de user247686 você pode ter atributos nó também.

Encontrado neste post https://stackoverflow.com/a/7684581/1395962

Exemplo:

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

Chamada como

xml_to_dict(root)

Você já tentou isso?

print xml.etree.ElementTree.tostring( conf_new )

forma mais directa para mim:

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

XML tem um infoset rico, e leva alguns truques especiais para representar isso em um dicionário Python. Elementos são ordenados, os atributos são distinguidos dos corpos de elementos, etc.

Um projeto para lidar com round-trips entre XML e dicionários Python, com algumas opções de configuração para lidar com as vantagens e desvantagens de diferentes maneiras é Suporte XML em Decapagem Ferramentas . Versão 1.3 e mais recentes é necessária. Não é pura Python (e na verdade é projetado para tornar a interação C ++ / Python mais fácil), mas pode ser apropriado para vários casos de uso.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top