How to replace node values in XML with Python

纵然是瞬间 提交于 2019-12-24 09:00:09

问题


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


回答1:


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>


来源:https://stackoverflow.com/questions/8236107/how-to-replace-node-values-in-xml-with-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!