【问题标题】:Updating coordinates in a KML file using python使用 python 更新 KML 文件中的坐标
【发布时间】:2016-06-14 19:00:23
【问题描述】:

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

<?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 导入解析器 from 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) 它只更新第一个分支(我怎样才能将它缩放以再重复 2,000 次?

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

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

抱歉,如果这是一个过于深入的问题,我已经为此苦苦挣扎了太久,似乎应该有一个我想念的简单方法。提前感谢您的帮助。

【问题讨论】:

  • 等一下,实际上我之前在 Python 中做过几乎完全相同的事情,让我把链接给你
  • 好的,我不确定这会有多大帮助,但看看github.com/thatchej/kml-parse/blob/master/parse_kml.py 可能会很好
  • 谢谢 Jaron,这确实帮助了我一些。我想出了使用你的正则表达式函数迭代树的人,我可以抓取和更新坐标,但我不知道如何将值存储在树中,我想我会更加努力得到它。
  • 是的,您可以看到我的用例略有不同,因为我需要创建大量不同的文件,因此我可以适当地重写它们。就地重写文件是 Python 的一个相当困难的问题。几个(可能是hacky)解决方案可以完全按照您的需要重写整个文件,或者以某种方式使用subprocess.popen() 来使用awk 进行更改。这些可能是非常平庸的解决方案,所以对它们持保留态度:)
  • 另请参阅:使用正则表达式解析 HTML/XML/KML:stackoverflow.com/questions/1732348/…

标签: python-2.7 kml elementtree pykml


【解决方案1】:

回答了我自己的问题。感谢 Jaron 让我摆脱困境(尽管我最终没有使用正则表达式,而是使用元素树)。一旦我更熟悉在嵌套树中导航,我就设法弄清楚了。还有助于更熟悉 .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

【讨论】:

    猜你喜欢
    • 2012-11-22
    • 1970-01-01
    • 1970-01-01
    • 2013-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-22
    • 1970-01-01
    相关资源
    最近更新 更多