删除跨越xml树分支的2个标记之间的所有内容

时间:2010-08-04 01:20:44

标签: python xml lxml

我正在尝试使用python和amp;删除2个标记之间的XML文档中的所有内容。 LXML。问题是标签可以在树的不同分支中(但总是在相同的深度),示例文档可能看起来像这样。

<root>
    <p> Hello world <start />this is a paragraph </p>
    <p> Goodbye world. <end />I'm leaving now </p>
</root>

我想删除开始和结束标记之间的所有内容。这将导致单个p标签:

<root>
    <p> Hello world I'm leaving now </p>
</root>

有没有人知道如何使用lxml&amp; amp;蟒?

3 个答案:

答案 0 :(得分:1)

你的手上乱七八糟,应该拍打那些故意歪曲XML嵌套规则的人。

您可能最好使用SAX之类的内容来识别<start/>标记,并在点击<end/>之前开始丢弃输入。 SAX在这里优于lxml,因为它允许你在每个lexeme中采取任意操作,而lxml在你触摸它们之前已经离开了开始和结束。

当您使用它时,您可能希望将这些文档转换为可用的XML。

答案 1 :(得分:1)

我知道有些人会想要为此辩护,但你可以使用正则表达式:

import re
new_string = re.sub(r'<start />(.*?)<end />', '', your_string, re.S)

如果XML解析器不是有效的XML,则无法使用它。

答案 2 :(得分:0)

您可以尝试使用类似SAX的target parser interface

from lxml import etree

class SkipStartEndTarget:
    def __init__(self, *args, **kwargs):
        self.builder = etree.TreeBuilder()
        self.skip = False

    def start(self, tag, attrib, nsmap=None):
        if tag == 'start':
            self.skip = True
        if not self.skip:
            self.builder.start(tag, attrib, nsmap)

    def data(self, data):
        if not self.skip:
            self.builder.data(data)

    def comment(self, comment):
        if not self.skip:
            self.builder.comment(self)

    def pi(self, target, data):
        if not self.skip:
            self.builder.pi(target, data)

    def end(self, tag):
        if not self.skip:
            self.builder.end(tag)
        if tag == 'end':
            self.skip = False

    def close(self):
        self.skip = False
        return self.builder.close()

然后,您可以使用SkipStartEndTarget类制作parser target,并使用该目标创建自定义XMLParser,如下所示:

parser = etree.XMLParser(target=SkipStartEndTarget())

如果需要,您仍然可以为解析器提供其他解析器选项。然后,您可以将此解析器提供给您正在使用的解析器函数,例如:

elem = etree.fromstring(xml_str, parser=parser)

这也适用于etree.XML()etree.parse(),您甚至可以将解析器设置为etree.setdefaultparser()的默认解析器(这可能不是一个好主意)。有一件事可能会让你感到惊讶:即使使用etree.parse(),这也不会返回元素树,但总是一个元素(如etree.XML()etree.fromstring()所做)。我不认为这可以(但是),所以如果这对你来说是一个问题,你将不得不以某种方式解决它。

请注意,也可以使用带有lxml.sax的sax事件创建一个elementtree,这可能有点困难和慢。与上面的示例相反,它将返回一个elementtree,但我认为它不提供正常使用.docinfo时会得到的etree.parse()。我也相信它(目前)不支持评论和pi。 (还没用过,所以我现在不能再精确了)

另请注意,任何类似SAX的解析文档的方法都要求跳过<start/><end/>之间的所有内容仍然会生成格式正确的文档,在您的示例中就是这种情况,但是例如,如果第二个<p><p2>,则不会是这种情况,因为您最终会得到<p>....</p2>