代码之家  ›  专栏  ›  技术社区  ›  dwich

如何使用python从XML中删除元素

  •  9
  • dwich  · 技术社区  · 16 年前

    我被XML和Python困住了。这项任务很简单,但到目前为止我还不能解决,花了那么长时间。我来这里是想咨询一下如何用几条线来解决这个问题。

    谢谢你帮我穿越这棵树。我总是以元素太多或太少而告终。元素可以无限嵌套。举个例子就是一个例子。我会接受任何解决方案,而不是对dom、minidom、sax等挑剔。

    我有一个与此类似的XML文件:

    <root>
        <elm>
            <elm>Common content</elm>
    
            <elm xmlns="http://example.org/ns">
                <elm lang="en">Content EN</elm>
                <elm lang="cs">žluťoučký koníček</elm>
            </elm>
    
            <elm xml:id="abc123">Common content</elm>
    
            <elm lang="en">Content EN</elm>
            <elm lang="cs">Content CS</elm>
    
            <elm lang="en">
                <elm>Content EN</elm>
                <elm>Content EN</elm>
            </elm>
    
            <elm lang="cs">
                <elm>Content CS</elm>
                <elm>Content CS</elm>
            </elm>
        </elm>
    </root>
    

    我需要的是-解析XML并编写一个新文件。新文件应包含给定语言的所有元素和不包含 lang 属性。

    对于“cs”语言,输出文件应包含以下内容:

    <root>
        <elm>
            <elm>Common content</elm>
    
            <elm xmlns="http://example.org/ns">
                <elm lang="cs">žluťoučký koníček</elm>
            </elm>
    
            <elm xml:id="abc123">Common content</elm>
    
            <elm lang="cs">Content CS</elm>
    
            <elm lang="cs">
                <elm>Content CS</elm>
                <elm>Content CS</elm>
            </elm>
        </elm>
    </root>
    

    如果你能省略 新文件中的属性,更好。但这并不重要。

    更新1: 添加了Unicode字符和命名空间属性。

    更新2: 使用python 2.5,首选标准库。

    3 回复  |  直到 10 年前
        1
  •  10
  •   Gal Bracha    10 年前

    使用 lxml :

    import lxml.etree as le
    
    with open('doc.xml','r') as f:
        doc=le.parse(f)
        for elem in doc.xpath('//*[attribute::lang]'):
            if elem.attrib['lang']=='en':
                elem.attrib.pop('lang')
            else:
                parent=elem.getparent()
                parent.remove(elem)
        print(le.tostring(doc))
    

    产量

    <root>
        <elm>Common content</elm>
    
        <elm>
            <elm>Content EN</elm>
            </elm>
    
        <elm>Common content</elm>
    
        <elm>Content EN</elm>
        <elm>
            <elm>Content EN</elm>
            <elm>Content EN</elm>
        </elm>
    
        </root>
    
        2
  •  5
  •   Alex Martelli    16 年前

    我不知道如何最好地移除 lang 属性,但这里有一些代码可以进行其他更改(python 2.7;对于2.5或2.6,使用 getIterator 而不是 iter ,假定在删除元素时,也始终希望删除该元素中包含的所有内容。

    这段代码只是将结果打印到标准输出(当然,您可以根据自己的意愿将其重定向,或者直接将其写入一些新文件,等等):

    import sys
    from xml.etree import cElementTree as et
    
    def picklang(path, lang='en'):
        tr = et.parse(path)
        for element in tr.iter():
            for subelement in element:
                la = subelement.get('lang')
                if la is not None and la != lang:
                    element.remove(subelement)
        return tr
    
    if __name__ == '__main__':
        tr = picklang('la.xml')
        tr.write(sys.stdout)
        print
    

    la.xml 作为你的例子,这写道

    <root>
        <elm>Common content</elm>
    
        <elm>
            <elm lang="en">Content EN</elm>
            </elm>
    
        <elm>Common content</elm>
    
        <elm lang="en">Content EN</elm>
        <elm lang="en">
            <elm>Content EN</elm>
            <elm>Content EN</elm>
        </elm>
    
        </root>
    
        3
  •  1
  •   bhuvi    10 年前

    更新@alex martelli的代码以删除元素列表更新到位的bug。如果输入稍微复杂一点,上面的解决方案会给出错误的答案。

    import sys
    from xml.etree import cElementTree as et
    
    def picklang(path, lang='en'):
        tr = et.parse(path)
        for element in tr.iter():
            for subelement in element[:]:
                la = subelement.get('lang')
    
                if la is not None and la != lang:
                    element.remove(subelement)
        return tr
    
    if __name__ == '__main__':
        tr = picklang('la.xml')
        tr.write(sys.stdout)
        print
    

    第7行代码 for subelement in element: 改为 for subelement in element[:]: 因为在遍历列表时不正确地就地更新列表。

    此代码迭代元素列表的副本,并在lang时删除元素!=原始元素列表中的“en”。