Как удалить элементы из XML с помощью Python - PullRequest
9 голосов
/ 29 августа 2010

Я застрял с 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: Добавлены символы Юникода и атрибут пространства имен.

UPDATE2: При использовании Python 2.5 предпочтительнее использовать стандартные библиотеки.

Ответы [ 3 ]

10 голосов
/ 29 августа 2010

Использование 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>
5 голосов
/ 29 августа 2010

Я не уверен, как лучше удалить атрибут 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>
1 голос
/ 17 ноября 2015

обновление кода @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" в исходном списке элементов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...