Python 解析XML文件,首先通过解析一个XML(Extensible Markup Language)文件获得原始经纬度数据。该过程将展示封装Python中不那么函数式的一些语言特征,来生成一组可迭代序列的方法。
借助xml.etree
模块,解析后返回的ElementTree
对象通过findall()
方法遍历处理后的数据。
待处理的目标数据的XML代码如下所示:
<Placemark><Point>
<coordinates>-76.33029518659048,
37.54901619777347,0</coordinates>
</Point></Placemark>
该文件包含多个<Placemark>
标签,每个这样的标签中又包含点和坐标结构体,这是包含地理位置信息的KML(Keyhole Markup Language)文件的典型格式。
解析XML文件的方法可以抽象为两个层次,底层方法负责定位各种标签、属性值以及文档内容,上层方法负责从文本和属性值中抽取有用的对象。
底层处理方法如下所示:
import xml.etree.ElementTree as XML
from typing import Text, List, TextIO, Iterable
def row_iter_kml(file_obj: TextIO) -> Iterable[List[Text]]:
ns_map = {
"ns0": "http://www.opengis.net/kml/2.2",
"ns1": "http://www.google.com/kml/ext/2.2"}
path_to_points= ("./ns0:Document/ns0:Folder/ns0:Placemark/"
"ns0:Point/ns0:coordinates")
doc = XML.parse(file_obj)
return (comma_split(Text(coordinates.text))
for coordinates in
doc.findall(path_to_points, ns_map))
函数以with
语句中文件对象的文本为输入,返回结果是基于经纬度数值对创建的生成器,用于生成包含数据的列表对象。解析XML文件的过程中,该函数包含一个简单的静态字典对象和ns_map
对象,提供作为搜索目标的XML标签的命名空间映射信息,字典对象则供负责处理XML文件的ElementTree.findall()
方法使用。
解析的主体是一个生成器函数,通过doc.findall()
方法定位一系列标签,这些标签作为comma_split()
函数的参数,把目标文本转换为一组以逗号分隔的序列值。
其中的comma_split()
是字符串split()
方法的函数版本,具体实现如下:
def comma_split(text: Text) -> List[Text]:
return text.split(",")
通过将对象方法包装为前缀式函数,保证了语言风格的统一。另外通过添加类型标示,明确指出函数将文本转换成了由文本值组成的列表。如果没有类型标示,将会有两个不同的split()
潜在实现:分割字节数组的和分割字符串的。在Python 3中,类型Text
是str
的别名。
函数的返回结果是由行数据组成的可迭代序列,每行包含3个字符串,分别代表路径上一个点的经度、纬度和海拔高度。至此,数据仍不可用,需要进一步抽取经度值和纬度值,并把它们转换为浮点数。
底层解析方法将原始数据转换为可迭代元组(或者序列),使得我们能以相对简单一致的方法处理数据文件。第3章介绍了如何将CSV(comma separated values,逗号分隔值)文件转换为元组序列。第6章将详述该话题,介绍不同的解析方法。
上面函数的解析结果如下所示:
[['-76.33029518659048', '37.54901619777347', '0'],
['-76.27383399999999', '37.840832', '0'],
['-76.459503', '38.331501', '0'],
etc.
['-76.47350299999999', '38.976334', '0']]
每一行是<ns0:coordinates>
标记文本经其中的逗号分隔之后得到的列表,包括东西向经度、北南向纬度及海拔高度。稍后将继续创建函数来处理这些计算结果,以得到最终可用的数据。