在lxml元素中如何查找CDATA?

3 投票
1 回答
1422 浏览
提问于 2025-04-18 16:19

我需要解析并重建一个文件格式,这个格式是由一个只能勉强称之为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 值

撰写回答