Herramientas de escritura XML para Python

Actualmente estoy probando ElementTree y se ve bien, se escapa de las entidades HTML y así sucesivamente. ¿Me estoy perdiendo algo realmente maravilloso que no conozco?

Esto es similar a lo que realmente estoy haciendo:

import xml.etree.ElementTree as ET root = ET.Element('html') head = ET.SubElement(root,'head') script = ET.SubElement(head,'script') script.set('type','text/javascript') script.text = "var a = 'I love á letters'" body = ET.SubElement(root,'body') h1 = ET.SubElement(body,'h1') h1.text = "And I like the fact that 3 > 1" tree = ET.ElementTree(root) tree.write('foo.xhtml') # more foo.xhtml var a = 'I love á letters'

And I like the fact that 3 > 1

Supongo que en realidad estás creando un árbol de DOM XML, porque quieres validar que lo que se incluye en este archivo es un XML válido, ya que de lo contrario solo escribirías una cadena estática en un archivo. Si tu objective es validar tu salida, entonces te sugiero

 from xml.dom.minidom import parseString doc = parseString("""     

And I like the fact that 3 > 1

""") with open("foo.xhtml", "w") as f: f.write( doc.toxml() )

Esto le permite simplemente escribir el XML que desea generar, validar que es correcto (ya que parseString generará una excepción si no es válido) y que su código se vea mucho mejor.

Es de suponer que no solo estás escribiendo el mismo XML estático cada vez y quieres alguna sustitución. En este caso tendría líneas como

 var a = '%(message)s' 

y luego usa el operador% para hacer la sustitución, como

 """ % {"message": "I love á letters"}) 

Otra forma es usar el constructor E Factory desde lxml (también disponible en Elementtree )

 >>> from lxml import etree >>> from lxml.builder import E >>> def CLASS(*args): # class is a reserved word in Python ... return {"class":' '.join(args)} >>> html = page = ( ... E.html( # create an Element called "html" ... E.head( ... E.title("This is a sample document") ... ), ... E.body( ... E.h1("Hello!", CLASS("title")), ... Ep("This is a paragraph with ", Eb("bold"), " text in it!"), ... Ep("This is another paragraph, with a", "\n ", ... Ea("link", href="http://www.python.org"), "."), ... Ep("Here are some reserved characters: ."), ... etree.XML("

And finally an embedded XHTML fragment.

"), ... ) ... ) ... ) >>> print(etree.tostring(page, pretty_print=True)) This is a sample document

Hello!

This is a paragraph with bold text in it!

This is another paragraph, with a link.

Here are some reservered characters: <spam&egg>.

And finally an embedded XHTML fragment.

Siempre hay SimpleXMLWriter , parte del kit de herramientas de ElementTree. La interfaz es muy simple.

Aquí hay un ejemplo:

 from elementtree.SimpleXMLWriter import XMLWriter import sys w = XMLWriter(sys.stdout) html = w.start("html") w.start("head") w.element("title", "my document") w.element("meta", name="generator", value="my application 1.0") w.end() w.start("body") w.element("h1", "this is a heading") w.element("p", "this is a paragraph") w.start("p") w.data("this is ") w.element("b", "bold") w.data(" and ") w.element("i", "italic") w.data(".") w.end("p") w.close(html) 

https://github.com/galvez/xmlwitch :

 import xmlwitch xml = xmlwitch.Builder(version='1.0', encoding='utf-8') with xml.feed(xmlns='http://www.w3.org/2005/Atom'): xml.title('Example Feed') xml.updated('2003-12-13T18:30:02Z') with xml.author: xml.name('John Doe') xml.id('urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6') with xml.entry: xml.title('Atom-Powered Robots Run Amok') xml.id('urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a') xml.updated('2003-12-13T18:30:02Z') xml.summary('Some text.') print(xml) 

en realidad no quieres algo como:

 html(head(script(type='text/javascript', content='var a = ...')), body(h1('And I like the fact that 3 < 1'), p('just some paragraph')) 

Creo que vi algo así en alguna parte. Esto sería maravilloso.

EDIT: En realidad, fui y escribí una biblioteca hoy para hacer precisamente eso : magictree

Puedes usarlo así:

 from magictree import html, head, script, body, h1, p root = html( head( script('''var a = 'I love &aacute; letters''', type='text/javascript')), body( h1('And I like the fact that 3 > 1'))) # root is a plain Element object, like those created with ET.Element... # so you can write it out using ElementTree :) tree = ET.ElementTree(root) tree.write('foo.xhtml') 

La magia en magictree reside en cómo funcionan las importaciones: las fábricas de Element se crean cuando es necesario. Eche un vistazo a la fuente , se basa en una respuesta a otra pregunta de StackOverflow .

Terminé usando saxutils.escape (str) para generar cadenas XML válidas y luego validándolas con el enfoque de Eli para estar seguro de que no me perdí ninguna etiqueta

 from xml.sax import saxutils from xml.dom.minidom import parseString from xml.parsers.expat import ExpatError xml = '''\n \n%s\n''' % (self.encoding, saxutils.escape(title), saxutils.escape(time), saxutils.escape(date), saxutils.escape(url), saxutils.escape(contents)) try: minidoc = parseString(xml) catch ExpatError: print "Invalid xml" 

Para cualquiera que se encuentre con esto ahora, en realidad hay una forma de hacerlo escondido en la biblioteca estándar de Python en xml.sax.utils.XMLGenerator . Aquí hay un ejemplo de ello en acción:

 >>> from xml.sax.saxutils import XMLGenerator >>> import StringIO >>> w = XMLGenerator(out, 'utf-8') >>> w.startDocument() >>> w.startElement("test", {'bar': 'baz'}) >>> w.characters("Foo") >>> w.endElement("test") >>> w.endDocument() >>> print out.getvalue()  Foo 

Pruebe http://uche.ogbuji.net/tech/4suite/amara . Es bastante completo y tiene un conjunto sencillo de herramientas de acceso. Soporte normal de Unicode, etc.

 # #Output the XML entry # def genFileOLD(out,label,term,idval): filename=entryTime() + ".html" writer=MarkupWriter(out, indent=u"yes") writer.startDocument() #Test element and attribute writing ans=namespace=u'http://www.w3.org/2005/Atom' xns=namespace=u'http://www.w3.org/1999/xhtml' writer.startElement(u'entry', ans, extraNss={u'x':u'http://www.w3.org/1999/xhtml' , u'dc':u'http://purl.org/dc/elements/1.1'}) #u'a':u'http://www.w3.org/2005/Atom', #writer.attribute(u'xml:lang',unicode("en-UK")) writer.simpleElement(u'title',ans,content=unicode(label)) #writer.simpleElement(u'a:subtitle',ans,content=u' ') id=unicode("http://www.dpawson.co.uk/nodesets/"+afn.split(".")[0]) writer.simpleElement(u'id',ans,content=id) writer.simpleElement(u'updated',ans,content=unicode(dtime())) writer.startElement(u'author',ans) writer.simpleElement(u'name',ans,content=u'Dave ') writer.simpleElement(u'uri',ans, content=u'http://www.dpawson.co.uk/nodesets/'+afn+".xml") writer.endElement(u'author') writer.startElement(u'category', ans) if (prompt): label=unicode(raw_input("Enter label ")) writer.attribute(u'label',unicode(label)) if (prompt): term = unicode(raw_input("Enter term to use ")) writer.attribute(u'term', unicode(term)) writer.endElement(u'category') writer.simpleElement(u'rights',ans,content=u'\u00A9 Dave 2005-2008') writer.startElement(u'link',ans) writer.attribute(u'href', unicode("http://www.dpawson.co.uk/nodesets/entries/"+afn+".html")) writer.attribute(u'rel',unicode("alternate")) writer.endElement(u'link') writer.startElement(u'published', ans) dt=dtime() dtu=unicode(dt) writer.text(dtu) writer.endElement(u'published') writer.simpleElement(u'summary',ans,content=unicode(label)) writer.startElement(u'content',ans) writer.attribute(u'type',unicode("xhtml")) writer.startElement(u'div',xns) writer.simpleElement(u'h3',xns,content=unicode(label)) writer.endElement(u'div') writer.endElement(u'content') writer.endElement(u'entry')