使用lxml的etree创建doctype

19 投票
3 回答
16541 浏览
提问于 2025-04-15 12:14

我想在用LXML的etree生成的XML文档中添加文档类型声明(doctype)。

但是我不知道怎么添加doctype。直接把字符串写死或者拼接在一起都不是一个好办法。

我原本期待能像在etree中添加处理指令(PI)那样简单:

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

但对我来说,这个方法不管用。我该怎么用lxml在XML文档中添加doctype呢?

3 个回答

7

这里的PI实际上是作为“doc”的一个前置元素被添加的。所以,它并不是“doc”的子元素。你需要使用“doc.getroottree()”这个方法。

下面是一个例子:

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

使用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>
38

这个方法对我有效:

print etree.tostring(tree, pretty_print=True, xml_declaration=True, encoding="UTF-8", doctype="<!DOCTYPE TEST_FILE>")
11

你可以先用一个文档类型声明(doctype)来创建你的文档:

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

打印结果是:

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

如果你想给一些没有文档类型声明的XML添加一个,你可以先创建一个带有你想要的文档类型声明的文档(就像上面那样),然后把没有文档类型声明的XML复制到里面:

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")

打印结果是:

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

这就是你想要的吗?

撰写回答