Ошибка Python elementree при удалении тегов - PullRequest
0 голосов
/ 03 июня 2019

У меня есть такой код для удаления всех тегов с именем sysId из xml в функции root_compare:

   #removing sysId from comparison
    for rm1 in xml_root1.findall('.//sysId'):
    xml_root1.remove(rm1)

Код дает мне эту ошибку:

 File "/tmp/dev_uac_api2/uac_api_lib.py", line 105, in root_compare
    xml_root1.remove(rm1)
 File "/usr/lib64/python2.7/xml/etree/ElementTree.py", line 337, in remove
    self._children.remove(element)
  ValueError: list.remove(x): x not in list

Мне нужно просмотреть все элементы в xml, даже child, grandchild, и удалить те, которые называются sysId. Можете ли вы помочь мне решить эту проблему?

структура xml выглядит примерно так:

<root>
    <sysId></sysId>
    <b></b>
    <c>
        <sysId></sysId>
    </c>
    <d>
        <e>
            <sysId></sysId>
        </e>
    </d>
</root>

1 Ответ

1 голос
/ 03 июня 2019

Удаление элементов - это немного больше работы в ElementTree, чем в lxml, потому что lxml имеет функцию getparent().

В ElementTree сначала необходимо сопоставить родительский элемент удаляемого элемента.

Поддержка xpath ElementTree тоже невелика, поэтому .//*[sysId] не будет соответствовать первому элементу sysId, так как это прямой дочерний элемент корневого элемента. Вам придется удалить их отдельно.

Пример ...

import xml.etree.ElementTree as ET

xml = """<root>
    <sysId></sysId>
    <b></b>
    <c>
        <sysId></sysId>
    </c>
    <d>
        <e>
            <sysId></sysId>
        </e>
    </d>
</root>"""

root = ET.fromstring(xml)

# find/remove direct "sysId" children of root
for child in root.findall("sysId"):
    root.remove(child)

# find elements that contain a "sysId" child element
for parent in root.findall(".//*[sysId]"):
    # find/remove direct "sysId" children of parent
    for child in parent.findall("sysId"):
        parent.remove(child)

print ET.tostring(root)

Печатная продукция ...

<root>
    <b />
    <c>
        </c>
    <d>
        <e>
            </e>
    </d>
</root>

Вот пример lxml , чтобы показать разницу (тот же печатный вывод, что и выше) ...

from lxml import etree

xml = """<root>
    <sysId></sysId>
    <b></b>
    <c>
        <sysId></sysId>
    </c>
    <d>
        <e>
            <sysId></sysId>
        </e>
    </d>
</root>"""

root = etree.fromstring(xml)

for elem in root.xpath(".//sysId"):
    elem.getparent().remove(elem)

print etree.tostring(root)
...