Python如何提取含XML处理指令的非标准XML中的完整坐标数据?
问题描述
我用Python从非标准XML文件提取坐标数据,部分<coordinates>标签里包含XML处理指令,示例XML如下:
<?xml version="1.0" encoding="UTF-8"?> <kml> <Document> <Folder> <Placemark id="CAR1"> <coordinates> 28.236931382585154893,36.380279408060658852,200<?AtTime 0.000000?> 28.236862947306430982,36.380324400967296583,200<?AtTime 2.333333?> 28.236862521767100986,36.380323843439811071,200<?AtTime 2.500000?> </coordinates> </Placemark> <Placemark id="CAR2"> <coordinates> 28.236931382585154893,36.380279408060658852,200 28.236862947306430982,36.380324400967296583,200 28.236862521767100986,36.380323843439811071,200 </coordinates> </Placemark> </Folder> </Document> </kml>
我的测试代码:
from xml.dom import minidom myFile = "test.xml" mydoc = minidom.parse(myFile) items = mydoc.getElementsByTagName('Placemark') for elem in items: print("coordinates ",elem.attributes['id'].value) coorTag = elem.getElementsByTagName('coordinates') if len(coorTag) > 0: for elem in coorTag: theData = elem.firstChild.nodeValue print(theData)
当前输出:
coordinates CAR1 28.236931382585154893,36.380279408060658852,200 coordinates CAR2 28.236931382585154893,36.380279408060658852,200 28.236862947306430982,36.380324400967296583,200 28.236862521767100986,36.380323843439811071,200
期望输出:
coordinates CAR1 28.236931382585154893,36.380279408060658852,200<?AtTime 0.000000?> 28.236862947306430982,36.380324400967296583,200<?AtTime 2.333333?> 28.236862521767100986,36.380323843439811071,200<?AtTime 2.500000?> coordinates CAR2 28.236931382585154893,36.380279408060658852,200 28.236862947306430982,36.380324400967296583,200 28.236862521767100986,36.380323843439811071,200
请问如何获取包含XML处理指令的<coordinates>标签内的完整坐标数据?这是否是minidom的问题,有没有更合适的Python替代库?
解决方案
1. 修复minidom的处理逻辑
minidom会把XML处理指令(PI)识别为独立节点,而非文本节点的一部分,所以只取firstChild.nodeValue只能拿到第一个文本节点的内容,后续的处理指令和文本节点都会被忽略。
要获取<coordinates>内的完整内容,需要遍历该标签下的所有子节点,根据节点类型拼接内容:
- 文本节点(
nodeType == Node.TEXT_NODE):直接取nodeValue - 处理指令节点(
nodeType == Node.PROCESSING_INSTRUCTION_NODE):拼接成<?target data?>格式的字符串
修改后的代码:
from xml.dom import minidom from xml.dom.minidom import Node myFile = "test.xml" mydoc = minidom.parse(myFile) items = mydoc.getElementsByTagName('Placemark') for elem in items: print("coordinates ", elem.attributes['id'].value) coorTag = elem.getElementsByTagName('coordinates') if len(coorTag) > 0: for coor_elem in coorTag: full_content = [] for child in coor_elem.childNodes: if child.nodeType == Node.TEXT_NODE: full_content.append(child.nodeValue) elif child.nodeType == Node.PROCESSING_INSTRUCTION_NODE: pi_str = f"<?{child.target} {child.data}?>" full_content.append(pi_str) print(''.join(full_content))
这段代码会遍历<coordinates>下的所有子节点,将文本和处理指令完整拼接,得到预期结果。
2. 更合适的替代库
如果经常处理这类非标准XML,推荐使用lxml库,它对XML节点的处理更灵活,能直接获取节点原始内容:
安装lxml
pip install lxml
使用lxml的代码示例
from lxml import etree myFile = "test.xml" tree = etree.parse(myFile) placemarks = tree.xpath('//Placemark') for pm in placemarks: pm_id = pm.get('id') print(f"coordinates {pm_id}") coor_elem = pm.find('coordinates') if coor_elem is not None: full_content = etree.tostring(coor_elem, encoding='unicode', method='text') print(full_content)
lxml的etree.tostring方法通过method='text'参数,可直接提取节点内的所有内容(包括处理指令),无需手动遍历节点,代码更简洁。
另外,BeautifulSoup也可将XML当作HTML解析处理,但lxml在XML领域的专业性更强。
内容的提问来源于stack exchange,提问作者Peter Lawrence
相关产品推荐
相关产品推荐

