views:

1110

answers:

3

I want to add doctypes to my XML documents that I'm generating with LXML's etree.

However I cannot figure out how to add a doctype. Hardcoding and concating the string is not an option.

I was expecting something along the lines of how PI's are added in etree:

pi = etree.PI(...)
doc.addprevious(pi)

But it's not working for me. How to add a to a xml document with lxml?

A: 

Apparently there is not such a way. You'll just have to write it to the document manually before writing the XML stream there.

Kamil Kisiel
Both links are 404's
Jon Hadley
+1  A: 

You can create your document with a doctype to begin with:

# Adapted from example on http://codespeak.net/lxml/tutorial.html
import lxml.etree as et
import StringIO
s = """<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root SYSTEM "test" [ <!ENTITY tasty "cheese"> 
<!ENTITY eacute "&#233;"> ]>
<root>
<a>&tasty; souffl&eacute;</a>
</root>
"""
tree = et.parse(StringIO.StringIO(s))
print et.tostring(tree, xml_declaration=True, encoding="utf-8")

prints:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE root SYSTEM "test" [
<!ENTITY tasty "cheese">
<!ENTITY eacute "&#233;">
]>
<root>
<a>cheese soufflé</a>
</root>

If you want to add a doctype to some XML that wasn't created with one, you can first create one with the desired doctype (as above), then copy your doctype-less XML into it:

xml = et.XML("<root><test/><a>whatever</a><end_test/></root>")
root = tree.getroot()
root[:] = xml
root.text, root.tail = xml.text, xml.tail
print et.tostring(tree, xml_declaration=True, encoding="utf-8")

prints:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE root SYSTEM "test" [
<!ENTITY tasty "cheese">
<!ENTITY eacute "&#233;">
]>
<root><test/><a>whatever</a><end_test/></root>

Is that what you're looking for?

RayG
A: 

The PI is actually added as a previous element from "doc". Thus, it's not a child of "doc". You must use "doc.getroottree()"

Here is an example:

>>> root = etree.Element("root")
>>> a  = etree.SubElement(root, "a")
>>> b = etree.SubElement(root, "b")
>>> root.addprevious(etree.PI('xml-stylesheet', 'type="text/xsl" href="my.xsl"'))
>>> print etree.tostring(root, pretty_print=True, xml_declaration=True, encoding='utf-8')
<?xml version='1.0' encoding='utf-8'?>
<root>
  <a/>
  <b/>
</root>

with getroottree():

>>> print etree.tostring(root.getroottree(), pretty_print=True, xml_declaration=True, encoding='utf-8')
<?xml version='1.0' encoding='utf-8'?>
<?xml-stylesheet type="text/xsl" href="my.xsl"?>
<root>
  <a/>
  <b/>
</root>
Bertrand Mathieu