1

I am new to Python. Now I have to replace a number of values in an XML file with Python. The example snippet of XML is:

<gmd:extent>
    <gmd:EX_Extent>
      <gmd:description gco:nilReason="missing">
        <gco:CharacterString />
      </gmd:description>
      <gmd:geographicElement>
        <gmd:EX_GeographicBoundingBox>
          <gmd:westBoundLongitude>
            <gco:Decimal>112.907</gco:Decimal>
          </gmd:westBoundLongitude>
          <gmd:eastBoundLongitude>
            <gco:Decimal>158.96</gco:Decimal>
          </gmd:eastBoundLongitude>
          <gmd:southBoundLatitude>
            <gco:Decimal>-54.7539</gco:Decimal>
          </gmd:southBoundLatitude>
          <gmd:northBoundLatitude>
            <gco:Decimal>-10.1357</gco:Decimal>
          </gmd:northBoundLatitude>
        </gmd:EX_GeographicBoundingBox>
      </gmd:geographicElement>
    </gmd:EX_Extent>
  </gmd:extent>

What I want to do is to replace those decimal values, i.e. 112.907, with a specified value.

<gmd:extent>
    <gmd:EX_Extent>
      <gmd:description gco:nilReason="missing">
        <gco:CharacterString />
      </gmd:description>
      <gmd:geographicElement>
        <gmd:EX_GeographicBoundingBox>
          <gmd:westBoundLongitude>
            <gco:Decimal>new value</gco:Decimal>
          </gmd:westBoundLongitude>
          <gmd:eastBoundLongitude>
            <gco:Decimal>new value</gco:Decimal>
          </gmd:eastBoundLongitude>
          <gmd:southBoundLatitude>
            <gco:Decimal>new value</gco:Decimal>
          </gmd:southBoundLatitude>
          <gmd:northBoundLatitude>
            <gco:Decimal>new value</gco:Decimal>
          </gmd:northBoundLatitude>
        </gmd:EX_GeographicBoundingBox>
      </gmd:geographicElement>
    </gmd:EX_Extent>
  </gmd:extent>

I tried with a few methods but none of them worked with my assumption that the difficulty is with the namespace prefix gmd and gco.

Please help me out. Thanks in advance!

Cheers, Alex

alextc
  • 3,206
  • 10
  • 63
  • 107

1 Answers1

3

I couldn't get lxml to process your xml without adding fake namespace declarations at the top so here is how your input looked

<gmd:extent xmlns:gmd="urn:x:y:z:1" xmlns:gco="urn:x:y:z:1">
    <gmd:EX_Extent>
        <gmd:description gco:nilReason="missing">
            <gco:CharacterString />
        </gmd:description>
        <gmd:geographicElement>
            <gmd:EX_GeographicBoundingBox>
                <gmd:westBoundLongitude>
                    <gco:Decimal>112.907</gco:Decimal>
                </gmd:westBoundLongitude>
                <gmd:eastBoundLongitude>
                    <gco:Decimal>158.96</gco:Decimal>
                </gmd:eastBoundLongitude>
                <gmd:southBoundLatitude>
                    <gco:Decimal>-54.7539</gco:Decimal>
                </gmd:southBoundLatitude>
                <gmd:northBoundLatitude>
                    <gco:Decimal>-10.1357</gco:Decimal>
                </gmd:northBoundLatitude>
            </gmd:EX_GeographicBoundingBox>
        </gmd:geographicElement>
    </gmd:EX_Extent>
</gmd:extent>

I assumed you have two lists one for the current values and one for the new ones like this

old = [112.907, 158.96, -54.7539, -10.1357] new = [1,2,3,4] d = dict(zip(old,new))

Here is the full code

#!/usr/bin/env python
import sys
from lxml import etree

def process(fname):
    f = open(fname)
    tree = etree.parse(f)
    root = tree.getroot()
    old = [112.907, 158.96, -54.7539, -10.1357]
    new = [1,2,3,4]
    d = dict(zip(old,new))
    nodes = root.findall('.//gco:Decimal', root.nsmap)
    for node in nodes:
        node.text = str(d[float(node.text)])
    f.close()
    return etree.tostring(root, pretty_print=True)

def main():
    fname = sys.argv[1]
    text = process(fname)
    outfile = open('out.xml', 'w+')
    outfile.write(text)
    outfile.close()

if __name__ == '__main__':
    main()

and here is how the output looked like

<gmd:extent xmlns:gmd="urn:x:y:z:1" xmlns:gco="urn:x:y:z:1">
    <gmd:EX_Extent>
        <gmd:description gco:nilReason="missing">
            <gco:CharacterString/>
        </gmd:description>
        <gmd:geographicElement>
            <gmd:EX_GeographicBoundingBox>
                <gmd:westBoundLongitude>
                    <gco:Decimal>1</gco:Decimal>
                </gmd:westBoundLongitude>
                <gmd:eastBoundLongitude>
                    <gco:Decimal>2</gco:Decimal>
                </gmd:eastBoundLongitude>
                <gmd:southBoundLatitude>
                    <gco:Decimal>3</gco:Decimal>
                </gmd:southBoundLatitude>
                <gmd:northBoundLatitude>
                    <gco:Decimal>4</gco:Decimal>
                </gmd:northBoundLatitude>
            </gmd:EX_GeographicBoundingBox>
        </gmd:geographicElement>
    </gmd:EX_Extent>
</gmd:extent>
Meitham
  • 9,178
  • 5
  • 34
  • 45
  • +1, because it made it even possible to attempt a VBScript (?horror?) solution here http://stackoverflow.com/a/15396987/603855. – Ekkehard.Horner Mar 13 '13 at 21:44