Adding attributes with ascending integer values to XML elements only if they have children

Question:

I want to add the add attribute ‘id="number"’ to an existing file.
id attributes should only be added if the element has at least one child.
So right now my XML file looks like this:

<Invoice>  
    <Fussteil>
       <Summen>
            <QF/>
            <UstSatz>21.00</UstSatz>
            <Betrag>
                <Bezeichnung>Steuerbetrag</Bezeichnung>
                <QF>124</QF>
                <Wert>8.8</Wert>
            </Betrag>
        </Summen>
        <Betrag>
            <Bezeichnung>Gesamtbetrag alle Zu/Abschläge</Bezeichnung>
            <QF>131</QF>
            <Wert>12.5</Wert>
        </Betrag>
        <Betrag/>
        <Betrag>
            <Bezeichnung>Gesamter Gebuehrenbetrag</Bezeichnung>
            <QF>176</QF>
            <Wert>8.8</Wert>
        </Betrag>
    </Fussteil>  
</Invoice>  

And in the end it should look like this:

<Invoice>  
    <Fussteil id="0">
       <Summen id="1">
            <QF/>
            <UstSatz>21.00</UstSatz>
            <Betrag id="2">
                <Bezeichnung>Steuerbetrag</Bezeichnung>
                <QF>124</QF>
                <Wert>8.8</Wert>
            </Betrag>
        </Summen>
        <Betrag id="3">
            <Bezeichnung>Gesamtbetrag alle Zu/Abschläge</Bezeichnung>
            <QF>131</QF>
            <Wert>12.5</Wert>
        </Betrag>
        <Betrag/>
        <Betrag id="4">
            <Bezeichnung>Gesamter Gebuehrenbetrag</Bezeichnung>
            <QF>176</QF>
            <Wert>8.8</Wert>
        </Betrag>
    </Fussteil>  
</Invoice>  

Have a solution that provides the following output:
So the only thing that is still a problem, is that an id is added to elements that do not have a child.


import xml.etree.ElementTree as ET

tree = ET.parse('file.xml')

val = 0

for elem in tree.iter():
    if elem.tag in ["Fussteil", "Summen", "Betrag"]:
        elem.set("id", str(val))
        val += 1 

tree.write('output.xml')


<Invoice>  
    <Fussteil id="0">
       <Summen id="1">
            <QF/>
            <UstSatz>21.00</UstSatz>
            <Betrag id="2">
                <Bezeichnung>Steuerbetrag</Bezeichnung>
                <QF>124</QF>
                <Wert>8.8</Wert>
            </Betrag>
        </Summen>
        <Betrag id="3">
            <Bezeichnung>Gesamtbetrag alle Zu/Abschläge</Bezeichnung>
            <QF>131</QF>
            <Wert>12.5</Wert>
        </Betrag>
        <Betrag id="4" />
        <Betrag id="5">
            <Bezeichnung>Gesamter Gebuehrenbetrag</Bezeichnung>
            <QF>176</QF>
            <Wert>8.8</Wert>
        </Betrag>
    </Fussteil>  
</Invoice> 
Asked By: JME

||

Answers:

Recursion is you friend here:

import xml.etree.ElementTree as ET

xml = '''<Invoice>  
    <Fussteil>
       <Summen>
            <QF/>
            <UstSatz>21.00</UstSatz>
            <Betrag>
                <Bezeichnung>Steuerbetrag</Bezeichnung>
                <QF>124</QF>
                <Wert>8.8</Wert>
            </Betrag>
        </Summen>
        <Betrag>
            <Bezeichnung>Gesamtbetrag alle Zu/Abschläge</Bezeichnung>
            <QF>131</QF>
            <Wert>12.5</Wert>
        </Betrag>
        <Betrag/>
        <Betrag>
            <Bezeichnung>Gesamter Gebuehrenbetrag</Bezeichnung>
            <QF>176</QF>
            <Wert>8.8</Wert>
        </Betrag>
    </Fussteil>  
</Invoice> '''

root = ET.fromstring(xml)

_id = -1


def inc() -> int:
    global _id
    _id += 1
    return _id


def add_id(node: ET.Element) -> None:
    lst = list(node)
    for ele in lst:
        if list(ele):
            ele.attrib['id'] = str(inc())
            add_id(ele)

add_id(root)
ET.dump(root)

output

<Invoice>  
    <Fussteil id="0">
       <Summen id="1">
            <QF />
            <UstSatz>21.00</UstSatz>
            <Betrag id="2">
                <Bezeichnung>Steuerbetrag</Bezeichnung>
                <QF>124</QF>
                <Wert>8.8</Wert>
            </Betrag>
        </Summen>
        <Betrag id="3">
            <Bezeichnung>Gesamtbetrag alle Zu/Abschläge</Bezeichnung>
            <QF>131</QF>
            <Wert>12.5</Wert>
        </Betrag>
        <Betrag />
        <Betrag id="4">
            <Bezeichnung>Gesamter Gebuehrenbetrag</Bezeichnung>
            <QF>176</QF>
            <Wert>8.8</Wert>
        </Betrag>
    </Fussteil>  
</Invoice>
Answered By: balderman