mokhtar omar
mokhtar omar

Reputation: 11

How to edit an XML file and save in new file?

I am working on data augmentation. I want to edit an XML file and save it to a new XML file. Here is an example of original XML file:

   <object>
       <name>car</name>
       <pose>Unspecified</pose>
       <truncated>0</truncated>
       <difficult>0</difficult>
       <bndbox>
         <xmin>670</xmin>
         <ymin>108</ymin>
         <xmax>947</xmax>
         <ymax>265</ymax>
       </bndbox>
     </object>
     <object>
       <name>number_plate</name>
       <pose>Unspecified</pose>
       <truncated>0</truncated>
       <difficult>0</difficult>
       <bndbox>
         <xmin>808</xmin>
         <ymin>210</ymin>
         <xmax>865</xmax>
         <ymax>232</ymax>
       </bndbox>
     </object>

Also, I want to change the value of xmin to xmin+100 and xmax to xmax+100. I tried the following code which does not generate any results:

   from PIL import Image
   import numpy as np
   import os
   import xml.etree.ElementTree as ET

   filename = ("/home/omarubuntu/PFEomar/depassement_stationnemen/conv-video_frame/Annotationflip_xml/")
   for image_name in os.listdir(filename):
       tree = ET.parse(filename+image_name)
       objs = tree.findall('object')
       for ix, obj in enumerate(objs):
           bbox = obj.find('bndbox')
           new_x1 = 1280-int(bbox.find('xmin').text)
           nex_y1 = int(bbox.find('ymin').text)
           new_x2 = 1280 - int(bbox.find('xmax').text)
           new_y2 = int(bbox.find('ymax').text)
             tree.write("/home/omarubuntu/PFEomar/depassement_stationnement/conv-video_frame/Annotationflip1_xml/"+image_name)

Upvotes: 1

Views: 691

Answers (2)

Cole Tierney
Cole Tierney

Reputation: 10314

If you only need to add 100 to xmin/xmax elements, you could use the xslt identity transform pattern and let libxml do the heavy lifting:

from lxml import etree

xsl = etree.XML('''
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <xsl:apply-templates/>
    </xsl:template>

    <!-- match xmin and xmax elements -->
    <xsl:template match="xmin|xmax">
        <xsl:copy>
            <!-- add 100 to the value of the current node -->
            <xsl:value-of select=". + 100" />
        </xsl:copy>
    </xsl:template>

    <!-- recursively copy the rest of the xml document -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>
''')

transform = etree.XSLT(xsl)
with open("original.xml") as f:
    print(transform(etree.parse(f)), end='')

Testing with diff:

diff original.xml <(./augmentation.py)
0a1
> <?xml version="1.0"?>
8c9
<           <xmin>670</xmin>
---
>           <xmin>770</xmin>
10c11
<           <xmax>947</xmax>
---
>           <xmax>1047</xmax>
20c21
<           <xmin>808</xmin>
---
>           <xmin>908</xmin>
22c23
<           <xmax>865</xmax>
---
>           <xmax>965</xmax>

If the stylesheet is stored in a file, augmentation.xsl, you can get the same results using the libxml utility, xsltproc:

diff original.xml <(xsltproc augmentation.xsl original.xml)

Upvotes: 1

furas
furas

Reputation: 142651

You get value from tree and change it but you are not putting it back to tree - ie.

xmin = bbox.find('xmin')
xmin.text = str(1280 - int(xmin.text))

And you are not using new name for file to save it.


This is your code with changes but I did't run it

import os
import xml.etree.ElementTree as ET

dirname = "/home/omarubuntu/PFEomar/depassement_stationnemen/conv-video_frame/Annotationflip_xml/"

for image_name in os.listdir(dirname):
    fullpath = os.path.join(dirname, image_name)

    tree = ET.parse(fullpath)

    objs = tree.findall('object')

    for ix, obj in enumerate(objs):
        bbox = obj.find('bndbox')

        xmin = bbox.find('xmin')
        xmin.text = str(1280 - int(xmin.text))

        xmax = bbox.find('xmax')
        xmax.text = str(1280 - int(xmax.text))

    new_fullpath = ospath.join(dirname, 'new_'+image_name)
    tree.write(new_fullpath)

This is code which I used to test it and it display xml with new values

import xml.etree.ElementTree as ET

text = '''<root>
     <object>
       <name>car</name>
       <pose>Unspecified</pose>
       <truncated>0</truncated>
       <difficult>0</difficult>
       <bndbox>
         <xmin>670</xmin>
         <ymin>108</ymin>
         <xmax>947</xmax>
         <ymax>265</ymax>
       </bndbox>
     </object>
     <object>
       <name>number_plate</name>
       <pose>Unspecified</pose>
       <truncated>0</truncated>
       <difficult>0</difficult>
       <bndbox>
         <xmin>808</xmin>
         <ymin>210</ymin>
         <xmax>865</xmax>
         <ymax>232</ymax>
       </bndbox>
     </object>
</root>'''


tree = ET.fromstring(text)

objs = tree.findall('object')

for ix, obj in enumerate(objs):
    bbox = obj.find('bndbox')

    xmin = bbox.find('xmin')
    xmin.text = str(1280 - int(xmin.text))

    xmax = bbox.find('xmax')
    xmax.text = str(1280 - int(xmax.text))

print(ET.tostring(tree).decode())

Upvotes: 2

Related Questions