5

I am trying to replace the element inside of bbox with a new set of coordinates.

my code :

    # import element tree
    import xml.etree.ElementTree as ET 


    #import xml file
    tree = ET.parse('C:/highway.xml')
    root = tree.getroot()

    #replace bounding box with new coordinates

    elem = tree.findall('bbox')
    elem.txt = '40.5,41.5,-12.0,-1.2'

my xml file:

   <geoEtl>
    <source>
        <server>localhost</server>
        <port>xxxx</port>
        <db>vxxx</db>
        <user>xxxx</user>
        <passwd>xxxx</passwd>
    </source>
    <targetDir>/home/firstuser/</targetDir>
    <bbox>-52.50,-1.9,52.45,-1.85</bbox>
    <extractions>
        <extraction>
            <table>geo_db_roads</table>
            <outputName>highways</outputName>
            <filter>highway = 'motorway'</filter>
            <geometry>way</geometry>
            <fields>
                <field>name</field>             
            </fields>
        </extraction>
    </extractions>
   </geoEtl>

have tried a variety of ways to do of things i found here but it doesnt seem to be working. thanks.

The error I'm receiving is as follows:

line 20, in <module> elem.txt = '40.5,41.5,-12.0,-1.2' AttributeError: 'list' object has no attribute 'txt' –
imjared
  • 19,492
  • 4
  • 49
  • 72
Moggy
  • 171
  • 1
  • 1
  • 9

4 Answers4

9

The findall function, as the name implies, finds all matching elements, not just one.

So, after this:

elem = tree.findall('bbox')

elem is a list of Elements. And, as with any other list, this:

elem.txt = '40.5,41.5,-12.0,-1.2'

Is going to give you an error:

AttributeError: 'list' object has no attribute 'txt'

If you want to do something to every member of a list, you have to loop over it:

elems = tree.findall('bbox')
for elem in elems:
    elem.txt = '40.5,41.5,-12.0,-1.2'
abarnert
  • 354,177
  • 51
  • 601
  • 671
  • ok awesome it runs no problem now, should be it rewriting the new coordinates on my XML file or is that a different issue? – Moggy Jul 02 '13 at 23:01
  • 2
    @Moggy: `ET.parse('C:/highway.xml')` just parses the file into a tree in memory. If you want to modify the XML file, you have to edit the tree, then _save it back to a file_`. You can do `tree.write('C:/highway.xml')` if you want to overwrite the original version with the new one. – abarnert Jul 02 '13 at 23:23
3

If your file isn't update it is most likely because you are not saving it, you can use the tree.write method to do just that.

tree.write('output.xml')
John
  • 13,197
  • 7
  • 51
  • 101
1
# import element tree
import xml.etree.ElementTree as ET 

#import xml file
tree = ET.parse('C:/highway.xml')
root = tree.getroot()

elems = root.findall(".//bbox")

for elem in elems:
    elem.text = '40.5,41.5,-12.0,-1.2'

tree.write('C:/highway.xml')
Taras
  • 717
  • 6
  • 4
0

If you want to replace the text of all boundingboxes with '40.5,41.5,-12.0,-1.2', try this

bboxes = tree.xpath('//bbox')
for bbox in bboxes:
    bbox.text= '40.5,41.5,-12.0,-1.2'
kamjagin
  • 3,614
  • 1
  • 22
  • 24
  • 2
    i get AttributeError: 'ElementTree' object has no attribute 'xpath' – Moggy Jul 02 '13 at 23:06
  • Yes - sorry. I also had slightly simpler code for parsing - I used etree as my base class and etree includes the xpath function. I had assumed that ElementTree has that too but I never double-checked it – kamjagin Jul 03 '13 at 11:12
  • @kamjagin: There is no class called `etree` anywhere. In both the 2.x and 3.x stdlibs, `etree` is a package with nothing in it but the `ElementTree` module; in the separately-installable module from Fredrick Lundh's website, nothing at all has that name; in `lxml`, `etree` is a module with roughly the same API as `ElementTree` in the others. `Element` handles XPath syntax in the `findall` method; in the `lxml` implementation you can also call it as `xpath`, but you still call it on `Element`s, not an empty package that you've somehow used as a base class. – abarnert Jul 03 '13 at 17:23