我首先会介绍一下我的问题的背景。
我在此站点上获得了世界各地领海的.kml文件,我想不在Google Earth上显示它,而是在matplotlib.pyplot图上显示它(如果可能的话也可以使用cartopy地图)。 .kml 文件如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2" xmlns:kml="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom">
<NetworkLink>
<name>Territorial Seas (12NM) v3</name>
<description><![CDATA[Flanders Marine Institute (2019). Maritime Boundaries Geodatabase: Territorial Seas (12NM), version 3. Available online at <a href="http://www.marineregions.org">http://www.marineregions.org</a> https://doi.org/10.14284/387. Consulted on YYYY-MM-DD.]]></description>
<Link>
<href>http://geo.vliz.be/geoserver/gwc/service/kml/MarineRegions:eez_12nm.png.kml</href>
</Link>
</NetworkLink>
</kml>
为此,我在 另一个 StackOverflow 问题上看到,使用 fastkml 读取文件是可能的。
所以这是我尝试运行的test.py代码(它来自使用指南):
from fastkml import kml
filename = "C:\\Users\\dumasal\\Documents\\GOOGLE_EARTH\\MarineRegions-eez_12nm.kml"
with open(filename, 'rt', encoding="utf-8") as myfile:
doc=myfile.read()
print(doc)
# Create the KML object to store the parsed result
k = kml.KML()
# Read in the KML string
k.from_string(doc)
print('k = ', k)
### Next we perform some simple sanity checks ###
# Check that the number of features is correct
# This corresponds to the single ``Document``
features = list(k.features())
print(len(features))
# Check that we can access the features as a generator
# (The two Placemarks of the Document)
print(features[0].features())
f2 = list(features[0].features())
print(len(f2))
# Check specifics of the first Placemark in the Document
print(f2[0])
print(f2[0].description)
print(f2[0].name)
# Check specifics of the second Placemark in the Document
print(f2[1].name)
f2[1].name = "ANOTHER NAME"
# Verify that we can print back out the KML object as a string
print(k.to_string(prettyprint=True))
当我运行它时,我收到错误:
ValueError: Unicode strings with encoding declaration are not supported. Please use bytes input or XML fragments without declaration.
。
我在谷歌上查找了错误,发现这个 GitHub 页面,他们说“from_string()”函数只需要字节,所以我的代码的开头可以更改为:
from fastkml import kml
filename = "C:\\Users\\dumasal\\Documents\\GOOGLE_EARTH\\MarineRegions-eez_12nm.kml"
with open(filename, 'r') as myfile:
doc=myfile.read().encode('UTF-8')
print(doc)
# Create the KML object to store the parsed result
k = kml.KML()
# Read in the KML string
k.from_string(doc)
print('k = ', k)
### Next we perform some simple sanity checks ###
# Check that the number of features is correct
# This corresponds to the single ``Document``
features = list(k.features())
print(len(features))
奇怪的是,ValueError 不再出现。但是现在我收到错误:
print(features[0].features())
IndexError: list index out of range
这是因为我的变量 features =
[]
,我不知道为什么。
那么您能否向我解释一下为什么 features 变量为空,或者使用 python 和 matplotlib 绘制 .kml 文件的更直接方法?
非常感谢!
一个问题是您拥有的 KML 文件是一个 super-overlay,它自动生成为子区域中引用为 NetworkLink 的多个 KML“文件”,并且很少有 KML python 包直接支持递归 NetworkLink。您正在使用的 fastkml 模块不实现 NetworkLinks,因此内容会被跳过。
pyKML包可以解析KML文件并迭代网络链接中引用的KML图层。
您可以执行类似的操作来迭代 NetworkLink 和 KML 内容。
import requests
import re
from pykml import parser
count = 0
def walk(elt):
global count
for elt in elt.getchildren():
tag = re.sub(r'^.*\}', '', elt.tag)
if tag in ['Folder', 'Document']:
walk(elt)
elif tag == 'NetworkLink':
print(tag)
print(elt.Link.href)
if count == 10:
# for debugging stop after 10 links
raise Exception("too many links")
count += 1
response = requests.get(elt.Link.href)
walk(parser.fromstring(response.content))
elif tag == 'GroundOverlay':
print(tag)
# do something with the ground overlay
else:
# other tag; e.g. Region, comment, etc
print(">>", tag)
with open("MarineRegions-eez_12nm.kml", 'rb') as myfile:
root = parser.parse(myfile).getroot()
walk(root)
MarineRegions KML 是一个超级叠加层,它递归地细分为更小的区域,因此尝试在所有级别绘制 GroundOverlay 将会用较小的高分辨率叠加层覆盖较大的低分辨率叠加层。您需要决定是否只需要高分辨率地面叠加层或低分辨率叠加层。例如,如果给定级别的 KML 内容没有任何 NetworkLink,则它处于最低级别。
注意 GeoServer 有两种不同类型的 super-overlays:栅格和矢量。您使用的 KML 是栅格超级叠加。您可能想检查是否有可用的矢量叠加,因为处理矢量可能比处理地面叠加图像更容易。