使用cleanup_namespaces无法移除XML命名空间,如何解决?
问题描述
我有如下XML字符串:
<exta> <signature>This </signature> <begin_date>2019-07-12T09:41:48.187</begin_date> <ver>4</ver> <maiden_bc>1549</maiden_bc> <exta_id>12345</exta_id> <nps_max_price xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <exta_id>72723</exta_id> <extended_datetime>2018-11-20T11:01:29.040</extended_datetime> <event_ind>E</event_ind> <maiden>12345</maiden> <patient_id>123</patient_id> <boss_id>123LHF</boss_id> <template_name/> <end_date>2019-01-01T00:00:00</end_date> <UYI_AMN xsi:nil="true"/> <dedt_bef_ATS xsi:nil="true"/> <form>W</form> </nps_max_price> </exta>
尝试使用cleanup_namespaces移除XML中的命名空间,代码如下:
from lxml import etree root = etree.fromstring(xml) for elem in root.getiterator(): elem.tag = etree.QName(elem).localname etree.cleanup_namespaces(root) print(etree.tostring(root).decode())
执行后输出仍保留xmlns:xsi和xsi:nil等命名空间相关内容,但期望移除所有命名空间相关内容,得到如下XML:
<exta> <signature>This </signature> <begin_date>2019-07-12T09:41:48.187</begin_date> <ver>4</ver> <maiden_bc>1549</maiden_bc> <exta_id>12345</exta_id> <nps_max_price> <exta_id>72723</exta_id> <extended_datetime>2018-11-20T11:01:29.040</extended_datetime> <event_ind>E</event_ind> <maiden>12345</maiden> <patient_id>123</patient_id> <boss_id>123LHF</boss_id> <template_name/> <end_date>2019-01-01T00:00:00</end_date> <UYI_AMN/> <dedt_bef_ATS/> <form>W</form> </nps_max_price> </exta>
解决方案
etree.cleanup_namespaces()只会清理未被使用的命名空间声明,但xsi:nil是正在被使用的属性,所以不会自动移除。要完全清除所有命名空间相关内容,需要手动处理:
- 遍历所有元素,移除带有命名空间的属性(如
xsi:nil) - 移除元素上的命名空间声明属性(如
xmlns:xsi) - 同时保留之前的标签本地名处理
修改后的代码如下:
from lxml import etree xml = ''' <exta> <signature>This </signature> <begin_date>2019-07-12T09:41:48.187</begin_date> <ver>4</ver> <maiden_bc>1549</maiden_bc> <exta_id>12345</exta_id> <nps_max_price xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <exta_id>72723</exta_id> <extended_datetime>2018-11-20T11:01:29.040</extended_datetime> <event_ind>E</event_ind> <maiden>12345</maiden> <patient_id>123</patient_id> <boss_id>123LHF</boss_id> <template_name/> <end_date>2019-01-01T00:00:00</end_date> <UYI_AMN xsi:nil="true"/> <dedt_bef_ATS xsi:nil="true"/> <form>W</form> </nps_max_price> </exta> ''' root = etree.fromstring(xml) # 处理所有元素 for elem in root.iter(): # 移除元素标签的命名空间,保留本地名 elem.tag = etree.QName(elem).localname # 移除所有带命名空间的属性和命名空间声明属性 to_remove = [] for attr_name in elem.attrib: # 带命名空间的属性键会包含{},比如{http://...}nil if '{' in attr_name or attr_name.startswith('xmlns:'): to_remove.append(attr_name) for attr in to_remove: del elem.attrib[attr] # 清理残留的空命名空间声明 etree.cleanup_namespaces(root) print(etree.tostring(root, encoding='unicode', pretty_print=True))
代码说明
- 使用
root.iter()遍历所有层级的元素,确保不遗漏子元素 - 替换元素标签为本地名,彻底去掉命名空间前缀
- 筛选并移除两类属性:带命名空间的属性(键含
{})和命名空间声明属性(以xmlns:开头) - 最后调用
cleanup_namespaces确保没有残留的无效命名空间声明
执行这段代码后,就能得到完全移除所有命名空间相关内容的XML。
内容的提问来源于stack exchange,提问作者Himanshu Poddar
相关产品推荐
相关产品推荐

