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>
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>
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>
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>