使用python更新KML文件中的坐标

时间:2016-06-14 19:00:23

标签: python-2.7 kml elementtree

我有一个看起来像这个文件的KML(只有“文档”部分再重复2000次左右,每个条目的坐标略有不同)。

<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.0">
    <Document>
        <Placemark>
            <Polygon>
                <extrude>1</extrude>
                <tesselate>1</tesselate>
                <altitudeMode>relativeToGround</altitudeMode>
                <outerBoundaryIs>
                    <LinearRing>
                        <coordinates>
                            -89.634425,40.73053,16  
                            -89.633951,40.73053,16  
                            -89.633951,40.73013,16  
                            -89.634425,40.73013,16
                        </coordinates>
                    </LinearRing>
                </outerBoundaryIs>
            </Polygon>
            <Style>
                <PolyStyle>
                    <color>#5a14F000</color>
                    <outline>1</outline>
                </PolyStyle>
            </Style>
        </Placemark>
    <Document> 
</kml>

该文件已从Google地球中导出。我正在尝试上传到映射工具(如CartoDB或Mapbox),但该文件因错误而被拒绝。我通过像这样的KML验证器运行文件:KMLValidator。我决定要上传的更改是:

1)将第2行替换为:

<kml xmlns="http://www.opengis.net/kml/2.2"
 xmlns:gx="http://www.google.com/kml/ext/2.2">

2)“关闭坐标”这意味着当前列出的坐标基本上是一个正方形(4个角),以满足验证器,我必须通过重复第一组坐标来关闭多边形。所以目标是:

                <coordinates>
                    -89.634425,40.73053,16  
                    -89.633951,40.73053,16  
                    -89.633951,40.73013,16  
                    -89.634425,40.73013,16
                    -89.634425,40.73053,16  
                </coordinates>

然而,我的问题是我无法以有效的方式更新坐标。到目前为止,这是我能想到的最好的(在this post的帮助下:

来自pykml导入解析器的

    来自os导入路径

from lxml import etree

kml_file = path.join( \
     'C:\Development', \
      'sample.kml')

# Source: https://stackoverflow.com/questions/13712132/extract-coordinates-from-kml-batchgeo-file-with-python
root = parser.fromstring(open(kml_file, 'r').read())

coordinates_before = root.Document.Placemark.Polygon.outerBoundaryIs.LinearRing.coordinates

# Print the coordinates  (only prints the first branch )
print 'coordinates before'
print coordinates_before

# Set the coordinates to a new value - Attempting to update to new values 
# Get Errors from this
root.Document.Placemark.Polygon.outerBoundaryIs.LinearRing.coordinates
= coordinates_before+"1,1,1"

coordinates_after = root.Document.Placemark.Polygon.outerBoundaryIs.LinearRing.coordinates

print 'coordinates after'
print coordinates_after


# # Create and store a string representation of full KML tree
root_string = etree.tostring(root, pretty_print=True)

# # # Print the string representation using pretty_print
print root_string

如您所见,我可以设法添加一组额外的值(1,1,1),但

a)我没有使用第一个坐标的值(而只是虚拟值)

b)它只更新第一个分支(如何将其缩放以重复另外2000次?

c)当我更新输出文件时也会显示此文本

 "coordinates xmlns:py="http://codespeak.net/lxml/objectify/pytype" py:pytype="str">"

道歉,如果这是一个过于深入的问题,我一直在努力解决这个问题太久了,似乎应该有一个我想念的简单方法。在此先感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

回答了我自己的问题。感谢Jaron让我失意(虽然我最终没有使用正则表达式,而是使用Element Tree)。一旦我更熟悉在嵌套树中导航,我就设法弄明白了。还有助于更熟悉.findall()并在for子句中使用它。谢谢!

def close_the_polygons(kml_file,color_name):
    # # Get the tree from KML File, add get color_name (only used when writing the file name )

    tree  = ET.parse(kml_file)
    root = tree.getroot()

    # iterate through tree to get to coordinate level

    for Document in root:
        for Placemark in Document.findall('Placemark'):
            for Polygon in Placemark.findall('Polygon'):
                for outerBoundaryIs in Polygon.findall('outerBoundaryIs'):
                    for LinearRing in outerBoundaryIs: # don't use Findall here because only 1 subelement
                        for coordinates in LinearRing: # don't use Findall here because only 1 subelement

                            ### convert the co-ordinate to text and delimiters become ordinary text (i.e. repr)
                            coordinates_text_before  =  repr(coordinates.text)

                            # ## Split the text (identifying the delimters)
                            coordinates_split_before = coordinates_text_before.split("\\t")

                            # # Store each entry of the array
                            entry_1 = coordinates_split_before[1]
                            entry_2 = coordinates_split_before[2][2:]
                            entry_3 = coordinates_split_before[3][2:]
                            entry_4 = coordinates_split_before[4][2:-10]
                            entry_5 = entry_1    #this solves the underlying problem of closing the polygon  

                            # # # consolidate into a single item array, goal with delimiters is to get it back to original text
                            string_updated_coordinates = "'\\n\\t"+entry_1+"\\t\\n"+entry_2+"\\t\\n"+entry_3+"\\t\\n"+entry_4+"\\t\\n"+entry_5+"\\n'"
                            updated_coordinates = literal_eval(string_updated_coordinates)

                            # # Store Updated Coordinates into original coordinates location
                            coordinates.text = updated_coordinates

    # # Write back to a file once all updates are complete
    tree = ET.ElementTree(root)
    tree.write('new_data_%s_closedPolygon_v1.0.kml' %color_name, xml_declaration=True)

    return