4

I have a existing xml file as following:

<vehicleTravelTimeMeasurements>
        <vehicleTravelTimeMeasurement name="ckkkkkkkkkk" no="2">
            <start link="1" pos="3.864983"/>
            <end link="3" pos="23.275375"/>
        </vehicleTravelTimeMeasurement>
        <vehicleTravelTimeMeasurement name="" no="3">
            <start link="1" pos="3.864983"/>
            <end link="2" pos="13.275375"/>
        </vehicleTravelTimeMeasurement>
</vehicleTravelTimeMeasurements>

I am trying to construct the same format as shown above by using xml.etree.cElementTree, and add them into the xml correctly:

new = ET.Element("vehicleTravelTimeMeasurement", name = "kkk", no = "4")
newsub1 =  ET.Element("start", link = "1", pos="3.88888")
newsub2 = ET.Element("end",link = "3", pos = "3.88888")

could someone help me out with this?

Thank you in advance!

Condo_programmer
  • 226
  • 1
  • 4
  • 12

2 Answers2

6

You wanted to use SubElement and add the start and end elements to the vehicleTravelTimeMeasurement element. Then insert that newly created element at position 2, since 0 and 1 are already occupied.

import xml.etree.ElementTree as ET

def indent(elem, level=0):
    i = "\n" + level*"  "
    if len(elem):
        if not elem.text or not elem.text.strip():
            elem.text = i + "  "
        if not elem.tail or not elem.tail.strip():
            elem.tail = i
        for elem in elem:
            indent(elem, level+1)
        if not elem.tail or not elem.tail.strip():
            elem.tail = i
    else:
        if level and (not elem.tail or not elem.tail.strip()):
            elem.tail = i

xml = '''<vehicleTravelTimeMeasurements>
        <vehicleTravelTimeMeasurement name="ckkkkkkkkkk" no="2">
            <start link="1" pos="3.864983"/>
            <end link="3" pos="23.275375"/>
        </vehicleTravelTimeMeasurement>
        <vehicleTravelTimeMeasurement name="" no="3">
            <start link="1" pos="3.864983"/>
            <end link="2" pos="13.275375"/>
        </vehicleTravelTimeMeasurement>
</vehicleTravelTimeMeasurements>'''

root = ET.fromstring(xml)
new = ET.Element("vehicleTravelTimeMeasurement", name = "kkk", no = "4")
newsub1 = ET.SubElement(new, "start", link = "1", pos="3.88888")
newsub2 = ET.SubElement(new, "end",link = "3", pos = "3.88888")
root.insert(2, new)
indent(root)
with open('test.xml', 'w') as f:
    f.write(ET.tostring(root))
heinst
  • 8,520
  • 7
  • 41
  • 77
0

Short version / Updates & Edits:

The only thing you need to do is (A) add newsub1 and newsub2 to new. And (B) add new to root.

root = ET.fromstring(xml)  # or whichever way you're getting `root`
# these 3 lines form your code:
new = ET.Element('vehicleTravelTimeMeasurement', name="kkk", no="4")
newsub1 = ET.Element('start', link='1', pos='3.88888')
newsub2 = ET.Element('end', link='3', pos='3.88888')
# the next steps to add
new.append(newsub1)
new.append(newsub2)
root.append(new)

Note that (A) & (B) can be done in any order and this can be shortened, as below:

>>> root = ET.fromstring(xml)
>>> new = ET.Element('vehicleTravelTimeMeasurement', name="kkk", no="4")
>>> root.append(new)  # note that I've immediately added `new`
>>> ET.SubElement(new, 'start', link='1', pos='3.88888')
<Element 'start' at 0x24707b8>
>>> ET.SubElement(new, 'end', link='3', pos='3.88888')
<Element 'end' at 0x24ea978>
>>> # there's no need to store the subelements in `newsub1` and
... # `newsub2` if you don't need to do anything with them
...
>>> indent(root)
>>> print ET.tostring(root)
<vehicleTravelTimeMeasurements>
  <vehicleTravelTimeMeasurement name="ckkkkkkkkkk" no="2">
    <start link="1" pos="3.864983" />
    <end link="3" pos="23.275375" />
  </vehicleTravelTimeMeasurement>
  <vehicleTravelTimeMeasurement name="" no="3">
    <start link="1" pos="3.864983" />
    <end link="2" pos="13.275375" />
  </vehicleTravelTimeMeasurement>
  <vehicleTravelTimeMeasurement name="kkk" no="4">
    <start link="1" pos="3.88888" />
    <end link="3" pos="3.88888" />
  </vehicleTravelTimeMeasurement>
</vehicleTravelTimeMeasurements>

Notes:

  1. I've added new to root just after creating it.
  2. Use append instead of insert if you know you're always appending, instead of needing to keep track of the no's in your original xml
    • unless you need to read that anyway to calculate the next 'no' attribute
  3. ET.SubElement(new) updates new (and root) even though new has already been appended.
  4. There's no need to store the subelements in newsub1 and newsub2 if you don't need to do anything with them.
    • First method (like yours) creates the elements and then adds them to root or new.
    • Second method uses ET.SubElement(new, ...) to add the elements to its parent.
  5. The function indent is from here, which quotes this source.

Re # 4.2 above, could also be done as:

root = ET.fromstring(xml)
new = ET.SubElement(root, 'vehicleTravelTimeMeasurement', name="kkk", no="4")
# `new` is already created as a subelement of `root` and appended
ET.SubElement(new, 'start', link='1', pos='3.88888')
ET.SubElement(new, 'end', link='3', pos='3.88888')

From the Subelement docs:

This function creates an element instance, and appends it to an existing element.

(emphasis mine)

Community
  • 1
  • 1
aneroid
  • 12,983
  • 3
  • 36
  • 66
  • Hi, thank you for the answer. could you please be more specific? – Condo_programmer Dec 31 '15 at 17:08
  • There was no `add_element`, I was thinking of `ET.SubElement(, ...)`. So that part of my answer was totally wrong. Also, the last code snippet in the edited answer is the _smallest_ change you'd need to make to do what you wanted. :-) – aneroid Jan 01 '16 at 09:52