Проследявайте родителските елементи с помощта на ElementTree

Ето моят XML:

<beans>
    <property name = "type1">
        <list>
            <bean class = "bean1">
                <property name = "typeb">
                    <value>foo</value>
                </property>
            </bean>
            <bean class = "bean2">
                <property name ="typeb">
                    <value>bar</value>
                </property>
            </bean>
        </list>
    </property>

    <property name = "type2">
        <list>
            <bean class = "bean3">
                <list>
                    <property name= "typec">
                        <sometags/>
                    </property>
                    <property name= "typed">
                        <list>
                            <value>foo</value>
                            <value>bar</bar>
                        </list>
                    </property> 
               </list>


            </bean>
        </list>
    </property>
</beans>

Сега това, което искаме да направим, е да сканираме това и да изтрием тези елементи:

            <bean class = "bean1">
                <property = "typeb">
                    <value>foo</value>
                </property>
            </bean>

И:

            <value>foo</value>

(от свойство class = "typed" елемент).

Сега, за да постигна това, това, което бих искал да направя, е нещо подобно:

for element in root.iter('value'):
    if element.text == 'foo':
        p1= element.getParent()
        if p1.tag == 'list': #second case scenario, remove just the value tag. 
            p1.remove(element)
        else: #first case scenario - remove entire bean
            p2 = p1.getParent()
            p3 = p2.getParent()
            p3.remove(p2)

Въпреки това ElementTree не поддържа дете да вижда своя родителски елемент.

Какъв би бил ефективният начин за постигане на това? Като се има предвид, че това е дълбока XML структура, не ми харесва много идеята за рекурсивна функция, която проверява типовете тагове на всяко ниво.


person dwjohnston    schedule 05.02.2014    source източник


Отговори (3)


с ElementTree използвайте родител, за да намерите подходящо дете:

>>> parent = root.find('.//bean[@class="bean1"]')
>>> parent
<Element 'bean' at 0x10eb31550>
>>> parent.find('.//value').text
'foo'
person Guy Gavriely    schedule 05.02.2014

Ето как го реших:

#gives you a list of every parent,child tuple
def iterparent(tree):
    for parent in tree.getiterator():
        for child in parent:
            yield parent, child

#recursive function. Deletes the given child node, from n parents back. 
#If n = 0 it deletes just the child. 
def removeParent(root, childToRemove, n):

    for parent, child in iterparent(root):
        if (childToRemove == child):
            if n>0:
                removeParent(root, parent, n-1)
            else: 
                parent.remove(child)


for parent, child in iterparent(root):
    if (child.tag == 'value' and (child.text in valuesToDelete):
        if (parent.tag == 'list'):
            removeParent(root, child, 0)
        else:
            removeParent(root, child, 2)    

Всъщност е доста елегантно. Харесва ми.

За моите цели това работи добре, но човек може да има затруднения с широк диапазон от елементи и дълбочини.

person dwjohnston    schedule 05.02.2014

Модулът lxml.etree има метод getparent. Предвид вашия примерен XML (е, след като поправих несъответстващия затварящ етикет), мога да направя следното:

>>> from lxml import etree
>>> 
>>> with open('data.xml') as fd:
...     doc = etree.parse(fd)
... 
>>> matches = doc.xpath('//value[text()="foo"]')
>>> element = matches[0]
>>> etree.tostring(element)
'<value>foo</value>\n        '
>>> parent = element.getparent()
>>> print etree.tostring(element)
<value>foo</value>

>>> parent = element.getparent()
>>> print etree.tostring(parent)
<property name="typeb">
          <value>foo</value>
        </property>
>>> parent = parent.getparent()
>>> print etree.tostring(parent)
<bean class="bean1">
        <property name="typeb">
          <value>foo</value>
        </property>
      </bean>

..и т.н.

person larsks    schedule 05.02.2014