我正在使用lxml和python 2.7来解析xml文件。我需要使用remove方法在某个时候删除一个元素,但非常奇怪的是它也删除了一些文本。
输入xml是:
cross-refs
然后我需要将cross-ref
元素展开为多个refid
,并将其分隔为<ce:para view="all">Web and grid services <ce:cross-ref refid="BIB10">[10]</ce:cross-ref><ce:cross-ref refid="BIB11">[11]</ce:cross-ref>, where they can provide rich service descriptions that can help in locating suitable services.</ce:para>
。所以输出应该是这样的:
xpath = "//ce:cross-refs"
cross_refs = tree.xpath(xpath, namespaces={'ce': 'http://www.elsevier.com/xml/common/dtd'})
for c in cross_refs:
c_parent = c.getparent()
c_values = c.text.strip("[]")
...
ref_ids = c.attrib['refid'].strip().split()
i = 0
for r in ref_ids:
...
tag = et.QName(CE, 'cross-ref')
exploded_cross_refs = et.Element(tag, refid=r, nsmap=NS_MAP)
exploded_cross_refs.text = "[" + c_values[i] + "]"
c.addprevious(exploded_cross_refs)
i += 1
c_parent.remove(c)
这里是python代码的缩写:
cross-refs
获取refid
元素,展开cross-ref
值和元素文本值,然后创建新的cross-refs
元素,并在原始cross-refs
之前添加它们,最后我想要删除旧的<ce:para view="all">Web and grid services <ce:cross-ref refid="BIB10">[10]</ce:cross-ref><ce:cross-ref refid="BIB11">[11]</ce:cross-ref></ce:para>
元素,我的问题就在这里:当我删除此元素时,结束标记和下一个元素之间的文本也会被删除,因此最终结果如下:
cross-ref
请注意,上一个para
和{{1}}元素之间的文字已被删除!我该如何解决这个问题?
答案 0 :(得分:1)
似乎是remove
方法,默认情况下会移除element.tail
。所以我用remove
方法替换strip_elements
,该方法采用with_tail
参数,因此您可以控制是否删除尾部。这是documentation,这是我使用的命令:
et.strip_elements(c_parent, 'cross-refs', with_tail=False)
答案 1 :(得分:1)
或者,特别是在不需要删除某个父级中某个名称的所有元素的情况下,我们可以创建一个简单的方法,将尾部附加到前一个元素(如果有),或者附加它否则,在元素实际删除之前的父文本:
def remove_preserve_tail(element):
if element.tail:
prev = element.getprevious()
parent = element.getparent()
if prev is not None:
prev.tail = (prev.tail or '') + element.tail
else:
parent.text = (parent.text or '') + element.tail
parent.remove(element)
<强>演示:强>
>>> from lxml import etree
>>> raw = '''<root>
... foo
... <div></div>has tail and no prev
... <br/><div></div>has tail and prev
... <br/>
... <div>no tail, whitespaces only</div>
... </root>'''
...
>>> root = etree.fromstring(raw)
>>> divs = root.xpath("//div")
>>> for div in divs:
... remove_preserve_tail(div)
...
>>> print etree.tostring(root)
<root>
foo
has tail and no prev
<br/>has tail and prev
<br/>
</root>