保留原始文档类型和lxml.etree解析的xml的声明 [英] Preserving original doctype and declaration of an lxml.etree parsed xml

查看:188
本文介绍了保留原始文档类型和lxml.etree解析的xml的声明的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用python的lxml,并且试图读取xml文档,对其进行修改并写回,但是原始的doctype和xml声明消失了.我想知道是否有一种简单的方法可以通过lxml或其他解决方案将其放回原处?

I'm using python's lxml and I'm trying to read an xml document, modify and write it back but the original doctype and xml declaration disappears. I'm wondering if there's an easy way of putting it back in whether through lxml or some other solution?

推荐答案

tl; dr

# adds declaration with version and encoding regardless of
# which attributes were present in the original declaration
# expects utf-8 encoding (encode/decode calls)
# depending on your needs you might want to improve that
from lxml import etree
from xml.dom.minidom import parseString
xml1 = '''\
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root SYSTEM "example.dtd">
<root>...</root>
'''
xml2 = '''\
<root>...</root>
'''
def has_xml_declaration(xml):
    return parseString(xml).version
def process(xml):
    t = etree.fromstring(xml.encode()).getroottree()
    if has_xml_declaration(xml):
        print(etree.tostring(t, xml_declaration=True, encoding=t.docinfo.encoding).decode())
    else:
        print(etree.tostring(t).decode())
process(xml1)
process(xml2)

以下内容将包括DOCTYPE和XML声明:

The following will include the DOCTYPE and the XML declaration:

from lxml import etree
from StringIO import StringIO

tree = etree.parse(StringIO('''<?xml version="1.0" encoding="iso-8859-1"?>
 <!DOCTYPE root SYSTEM "test" [ <!ENTITY tasty "eggs"> ]>
  <root>
   <a>&tasty;</a>
 </root>
'''))

docinfo = tree.docinfo
print etree.tostring(tree, xml_declaration=True, encoding=docinfo.encoding)

请注意,如果创建Element(例如,使用fromstring),tostring不会保留DOCTYPE,它仅在使用parse处理XML时有效.

Note, tostring does not preserve the DOCTYPE if you create an Element (e.g. using fromstring), it only works when you process the XML using parse.

更新:由 J.F.指出.塞巴斯蒂安(Sebastian)我对fromstring的主张不正确.

Update: as pointed out by J.F. Sebastian my assertion about fromstring is not true.

这里有一些代码来突出显示ElementElementTree序列化之间的区别:

Here is some code to highlight the differences between Element and ElementTree serialization:

from lxml import etree
from StringIO import StringIO

xml_str = '''<?xml version="1.0" encoding="iso-8859-1"?>
 <!DOCTYPE root SYSTEM "test" [ <!ENTITY tasty "eggs"> ]>
  <root>
   <a>&tasty;</a>
 </root>
'''

# get the ElementTree using parse
parse_tree = etree.parse(StringIO(xml_str))
encoding = parse_tree.docinfo.encoding
result = etree.tostring(parse_tree, xml_declaration=True, encoding=encoding)
print "%s\nparse ElementTree:\n%s\n" % ('-'*20, result)

# get the ElementTree using fromstring
fromstring_tree = etree.fromstring(xml_str).getroottree()
encoding = fromstring_tree.docinfo.encoding
result = etree.tostring(fromstring_tree, xml_declaration=True, encoding=encoding)
print "%s\nfromstring ElementTree:\n%s\n" % ('-'*20, result)

# DOCTYPE is lost, and no access to encoding
fromstring_element = etree.fromstring(xml_str)
result = etree.tostring(fromstring_element, xml_declaration=True)
print "%s\nfromstring Element:\n%s\n" % ('-'*20, result)

,输出为:

--------------------
parse ElementTree:
<?xml version='1.0' encoding='iso-8859-1'?>
<!DOCTYPE root SYSTEM "test" [
<!ENTITY tasty "eggs">
]>
<root>
   <a>eggs</a>
 </root>

--------------------
fromstring ElementTree:
<?xml version='1.0' encoding='iso-8859-1'?>
<!DOCTYPE root SYSTEM "test" [
<!ENTITY tasty "eggs">
]>
<root>
   <a>eggs</a>
 </root>

--------------------
fromstring Element:
<?xml version='1.0' encoding='ASCII'?>
<root>
   <a>eggs</a>
 </root>

这篇关于保留原始文档类型和lxml.etree解析的xml的声明的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆