【问题标题】:How to remove elements from XML using Python如何使用 Python 从 XML 中删除元素
【发布时间】:2010-08-29 01:38:42
【问题描述】:

我被 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>

如果您可以在新文件中省略lang 属性,那就更好了。但这并不重要。

UPDATE1:添加了 unicode 字符和命名空间属性。

UPDATE2:使用 Python 2.5,首选标准库。

【问题讨论】:

  • For "en" language the output file should containt this: 我假设您的意思是说给定的输出是针对“cs”语言的?
  • @LarsH:我更新了问题,在那里添加了一些 unicode 字符。你说得对,应该写:对于“cs”语言。会改的。

标签: python xml


【解决方案1】:

使用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>

【讨论】:

  • 非常感谢。无法在我的 WinXP 上安装 lxml,编译器有问题。稍后会试一试。
  • 有效!谢谢!你拯救了我的夜晚 :) 我感谢你们,两种解决方案都很好。
【解决方案2】:

我不确定如何最好地删除 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>

【讨论】:

  • 谢谢亚历克斯,效果很好。除了两件事 - 命名空间和 unicode。如果有 xmlns 属性,例如 &lt;elm xmlns="http://example.org/ns"&gt;,则新节点本身将获得 xmlns:ns0="http://example.org/ns" 属性,并且所有子节点都会获得 &lt;ns0: 前缀。这些前缀不在源文件中。也不能强制 write() 方法以原始形式写入 unicode 字符。我将更新示例文件。
  • @dwich,对于写作,您可以添加到write 调用您选择的encoding 参数。诸如名称空间问题(我相信它不会改变 XML 的语义)之类的美学问题要处理起来要棘手得多,唉(就像,例如,您可能已经注意到,输出中的缩进是不同的,因为在被移除的元素也会消失)。
  • 那个 unicode 是我的错误,我开始使用编解码器,即使我使用了encoding='utf-8',它也不起作用(因为打开它不正确)。感谢您的回答,我会选择 ~unutbu 的解决方案,因为他的代码在命名空间方面没有问题。两个答案都是正确的。谢谢你们!
  • @dwich,我同意你的看法——@unutbu 的答案更好(如果你可以使用 lxml 之类的第三方包),除其他外,因为它确实删除了你理想中的属性,而我的,正如我提到的,没有。
【解决方案3】:

更新@Alex Martelli 的代码以消除元素列表更新到位的错误。如果输入稍微复杂一点,上述解决方案将给出错误答案。

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" 时删除元素。

【讨论】:

    猜你喜欢
    • 2022-11-23
    • 1970-01-01
    • 1970-01-01
    • 2020-12-19
    • 1970-01-01
    • 2021-04-25
    • 1970-01-01
    • 2012-11-09
    • 2018-04-12
    相关资源
    最近更新 更多