Respostas:
Atualmente, a opção mais popular (e muito simples) é a API ElementTree , que foi incluída na biblioteca padrão desde o Python 2.5.
As opções disponíveis para isso são:
Aqui está um exemplo de como gerar seu documento de exemplo usando o in-stdlib cElementTree:
import xml.etree.cElementTree as ET
root = ET.Element("root")
doc = ET.SubElement(root, "doc")
ET.SubElement(doc, "field1", name="blah").text = "some value1"
ET.SubElement(doc, "field2", name="asdfasd").text = "some vlaue2"
tree = ET.ElementTree(root)
tree.write("filename.xml")
Eu testei e funciona, mas estou assumindo que o espaço em branco não é significativo. Se você precisar do recuo "prettyprint", informe-me e vou procurar como fazer isso. (Pode ser uma opção específica para LXML. Não uso muito a implementação stdlib)
Para mais leitura, aqui estão alguns links úteis:
Como observação final, cElementTree ou LXML devem ser rápidos o suficiente para todas as suas necessidades (ambos são código C otimizado), mas no caso de você estar em uma situação em que precisa extrair todo o desempenho, os benchmarks em o site LXML indica que:
xml_declaration=True
se você especificar uma codificação ... mas, para obter um comportamento equivalente, chame tree.write()
assim: tree.write("filename.xml", xml_declaration=True, encoding='utf-8')
Você pode usar qualquer codificação desde que especifique explicitamente 1. ( ascii
Forçará todos os caracteres Unicode fora do conjunto ASCII de 7 bits para ser codificado-entidade, se você não confiar em um servidor web para ser configurado corretamente.)
vlaue2
para value2
: O erro tipográfico é na saída XML solicitado na pergunta original. Até que isso mude, o erro de digitação aqui está correto.
cElementTree
foi depreciado em Python 3.3
A biblioteca lxml inclui uma sintaxe muito conveniente para geração de XML, chamada E-factory . Aqui está como eu daria o exemplo que você dá:
#!/usr/bin/python
import lxml.etree
import lxml.builder
E = lxml.builder.ElementMaker()
ROOT = E.root
DOC = E.doc
FIELD1 = E.field1
FIELD2 = E.field2
the_doc = ROOT(
DOC(
FIELD1('some value1', name='blah'),
FIELD2('some value2', name='asdfasd'),
)
)
print lxml.etree.tostring(the_doc, pretty_print=True)
Resultado:
<root>
<doc>
<field1 name="blah">some value1</field1>
<field2 name="asdfasd">some value2</field2>
</doc>
</root>
Ele também suporta a adição a um nó já criado, por exemplo, após o acima, você pode dizer
the_doc.append(FIELD2('another value again', name='hithere'))
getattr
, por exemplo getattr(E, "some-tag")
,.
O Yattag http://www.yattag.org/ ou https://github.com/leforestier/yattag fornece uma API interessante para criar esse documento XML (e também documentos HTML).
Está usando o gerenciador de contexto e a with
palavra - chave.
from yattag import Doc, indent
doc, tag, text = Doc().tagtext()
with tag('root'):
with tag('doc'):
with tag('field1', name='blah'):
text('some value1')
with tag('field2', name='asdfasd'):
text('some value2')
result = indent(
doc.getvalue(),
indentation = ' '*4,
newline = '\r\n'
)
print(result)
então você terá:
<root>
<doc>
<field1 name="blah">some value1</field1>
<field2 name="asdfasd">some value2</field2>
</doc>
</root>
Para a escolha mais simples, eu usaria o minidom: http://docs.python.org/library/xml.dom.minidom.html . Ele é incorporado à biblioteca padrão do python e é fácil de usar em casos simples.
Aqui está um tutorial bastante fácil de seguir: http://www.boddie.org.uk/python/XML_intro.html
Para uma estrutura XML tão simples, talvez você não queira envolver um módulo XML completo. Considere um modelo de string para as estruturas mais simples ou Jinja para algo um pouco mais complexo. O Jinja pode manipular o loop sobre uma lista de dados para produzir o xml interno da sua lista de documentos. Isso é um pouco mais complicado com modelos de strings python brutos
Para um exemplo de Jinja, veja minha resposta para uma pergunta semelhante .
Aqui está um exemplo de geração de seu xml com modelos de string.
import string
from xml.sax.saxutils import escape
inner_template = string.Template(' <field${id} name="${name}">${value}</field${id}>')
outer_template = string.Template("""<root>
<doc>
${document_list}
</doc>
</root>
""")
data = [
(1, 'foo', 'The value for the foo document'),
(2, 'bar', 'The <value> for the <bar> document'),
]
inner_contents = [inner_template.substitute(id=id, name=name, value=escape(value)) for (id, name, value) in data]
result = outer_template.substitute(document_list='\n'.join(inner_contents))
print result
Resultado:
<root>
<doc>
<field1 name="foo">The value for the foo document</field1>
<field2 name="bar">The <value> for the <bar> document</field2>
</doc>
</root>
O infortúnio da abordagem de modelo é que você não vai conseguir escapar de <
e >
para livre. Eu dancei em torno desse problema, puxando um utilitário dexml.sax
Acabei de escrever um gerador de xml, usando o método de modelos de bigh_29 ... é uma ótima maneira de controlar o que você produz sem que muitos objetos atrapalhem.
Quanto à tag e ao valor, usei duas matrizes, uma que forneceu o nome e a posição da tag no xml de saída e outra que referenciou um arquivo de parâmetro com a mesma lista de tags. O arquivo de parâmetro, no entanto, também possui o número da posição no arquivo de entrada (csv) correspondente de onde os dados serão obtidos. Dessa forma, se houver alguma alteração na posição dos dados provenientes do arquivo de entrada, o programa não será alterado; ele trabalha dinamicamente a posição do campo de dados a partir do tag apropriado no arquivo de parâmetros.