在lxml元素中如何查找CDATA?
我需要解析并重建一个文件格式,这个格式是由一个只能勉强称之为XML的解析器使用的。我明白,符合标准的XML对CDATA和空格并不在意,但不幸的是,这个应用程序要求我必须关注这两者...
我正在使用lxml.etree
,因为它在保留CDATA方面做得很好。
举个例子:
s = '''
<root>
<item>
<![CDATA[whatever]]>
</item>
</root>'''
import lxml.etree as et
et.fromstring(s, et.XMLParser(strip_cdata=False))
item = root.find('item')
print et.tostring(item)
这段代码输出:
<item>
<![CDATA[whatever]]>
</item>
lxml
完好无损地保留了<item>
标签的格式...太棒了!
问题是,我没有办法准确知道CDATA在标签文本中的开始和结束位置。属性item.text
并没有显示出文本中哪一部分是被CDATA包裹的:
item.text
==> '\n whatever\n '
所以如果我修改了它,然后试图把它作为CDATA输出,就会丢失空格的位置:
item.text = CDATA('foobar')
et.tostring(item)
==> '<item><![CDATA[foobar]]></item>\n'
显然,lxml
“知道”CDATA在节点文本中的位置,因为它通过node.tostring()
保留了它。不过,我找不到一种方法来查看文本中哪些部分是CDATA,哪些不是。有什么建议吗?
1 个回答
3
我不太确定 lxml
的情况,但使用 minidom
的话,你可以修改 CDATA 部分,同时保留周围的空白,因为 CDATASection
是一种独立的节点类型。
>>> from xml.dom import minidom
>>> data = minidom.parseString(s)
>>> parts = data.getElementsByTagName('item')
>>> item = parts[0]
>>> item.childNodes
[<DOM Text node "u'\n '">, <DOM CDATASection node "u'whatever'">, <DOM Text node "u'\n '">]
>>> item.childNodes[1].nodeValue = 'changed'
>>> print item.toxml()
<item>
<![CDATA[changed]]>
</item>
想了解更多细节,可以查看 xml.dom.minidom: 获取 CDATA 值。