Вставьте узел для элемента в XML с помощью Python/ElementTree

Мне нужно пройти по дереву XML, чтобы добавить подэлемент, когда значение меньше 5. Например, этот XML можно изменить на

<?xml version="1.0" encoding="UTF-8"?>
<A value="45">
    <B value="30">
        <C value="10"/>
        <C value ="20"/>
    </B>
    <B value="15">
        <C value = "5" />
        <C value = "10" />
    </B>
</A>

этот XML.

<?xml version="1.0" encoding="UTF-8"?>
<A value="45">
    <B value="30">
        <C value="10"/>               
        <C value ="20"/>
    </B>
    <B value="15">
        <C value = "5"><D name="error"/></C>
        <C value = "10" />
    </B>
</A>

Как я могу сделать это с ElementTree Python?


person prosseek    schedule 25.01.2011    source источник
comment
связанные: stackoverflow.com/questions/4788958/   -  person jfs    schedule 25.01.2011
comment
Может ли быть более одного ребенка <D>? Рассматривали ли вы вариант добавления атрибута error к элементу с проблемой?   -  person John Machin    schedule 25.01.2011


Ответы (2)


Вы, вероятно, сделали опечатку, потому что в примере элемент ошибки добавляется как дочерний элемент элемента, значение которого равно 10, что не меньше 5. Но я думаю, что идея заключается в следующем:

#!/usr/bin/env python

from xml.etree.ElementTree import fromstring, ElementTree, Element

def validate_node(elem):
    for child in elem.getchildren():
        validate_node(child)
        value = child.attrib.get('value', '')
        if not value.isdigit() or int(value) < 5:
            child.append(Element('D', {'name': 'error'}))

if __name__ == '__main__':
    import sys
    xml = sys.stdin.read() # read XML from standard input
    root = fromstring(xml) # parse into XML element tree
    validate_node(root)
    ElementTree(root).write(sys.stdout, encoding='utf-8')
            # write resulting XML to standard output

Учитывая этот ввод:

<?xml version="1.0" encoding="UTF-8"?>
<A value="45">
    <B value="30">
        <C value="1"/>
        <C value="20"/>
    </B>
    <B value="15">
        <C value="5" />
        <C value="10" />
        <C value="foo" />
    </B>
</A>

Это вывод:

<A value="45">
    <B value="30">
        <C value="1"><D name="error" /></C>
        <C value="20" />
    </B>
    <B value="15">
        <C value="5" />
        <C value="10" />
        <C value="foo"><D name="error" /></C>
    </B>
</A>
person scoffey    schedule 25.01.2011
comment
что меня беспокоит, так это то, что цикл for на всю глубину будет перебирать недавно добавленный дочерний элемент здесь? например. если for выполняется с for node in list(tree.getroot()) и где-то добавляется узел во время итерации. - person n611x007; 25.10.2013
comment
Итак, способ запустить это cat file.xml | python script.py? Я сделал, и это работает, но мне интересно, есть ли другой способ. - person fedorqui 'SO stop harming'; 24.11.2015

ElementTree iter (или getiterator для Python ‹2.7) будет рекурсивно возвращать все узлы в дереве, затем просто проверить ваше условие и создать Подэлемент:

from xml.etree import ElementTree as ET
tree = ET.parse(input)
for e in tree.getiterator():
    if int(e.get('value')) < 5:
        ET.SubElement(e,'D',dict(name='error'))
person Mark Tolonen    schedule 25.01.2011
comment
будет ли добавленный элемент получен итератором? Если да, то как я могу отличить новый элемент от уже существующих? - person n611x007; 25.10.2013