Python如何处理带命名空间的XML

Python处理带命名空间XML需显式声明命名空间映射字典,XPath中用“前缀:标签”形式查找,如ns:channel;默认命名空间也须指定前缀,URI必须完全匹配,不支持*通配符跨空间匹配。

Python处理带命名空间的XML,关键在于正确声明和使用命名空间前缀,否则findfindall等方法会找不到元素。

理解命名空间在ElementTree中的表示方式

ElementTree默认不自动识别XML文档中的xmlns声明。即使XML里写了xmlns="http://example.com/ns",你也不能直接用root.find("item")——必须显式传入命名空间映射字典。

  • 命名空间映射是一个字典,键是前缀(可自定义),值是URI字符串
  • XPath表达式中需用prefix:tagname写法,如"ns:item"
  • 默认命名空间(无前缀的xmlns="...")也要给它起个前缀,不能留空

使用namespaces参数进行查找

这是最常用也最推荐的方式:构造命名空间字典,传给findfindalliterfind等方法。

例如有如下XML:

立即学习“Python免费学习笔记(深入)”;



  
    My Feed
    Post 1
  

对应代码为:

import xml.etree.ElementTree as ET

tree = ET.parse("feed.xml") root = tree.getroot()

声明命名空间:这里用"ns"作为前缀

ns = {"ns": "https://www./link/ff4776b449efb88b35fbf6187af9771e"}

正确查找

channel = root.find("ns:channel", namespaces=ns) title = channel.find("ns:title", namespaces=ns) items = channel.findall("ns:item", namespaces=ns)

处理多个命名空间或带前缀的XML

如果XML中用了多个带前缀的命名空间(如xmlns:dc="http://purl.org/dc/elements/1.1/"),只需在字典中一并声明:

ns = {
    "rss": "https://www./link/ff4776b449efb88b35fbf6187af9771e",
    "dc": "http://purl.org/dc/elements/1.1/"
}

查找 dc:creator

creator = item.find("dc:creator", namespaces=ns)

注意:前缀名(如"dc")可以任意取,只要和XPath中一致即可;URI必须完全匹配XML中声明的值(包括末尾斜杠)。

避免常见坑:默认命名空间与通配符

ElementTree不支持*通配符跨命名空间匹配。不要写root.findall("*:item")——它不会生效。

  • 若不确定命名空间,可先用root.tag打印根元素全名,如{https://www./link/ff4776b449efb88b35fbf6187af9771e}rss,从中提取URI
  • 想忽略命名空间?可用正则提取本地名:elem.tag.split("}")[-1],再遍历比对,但性能较差,仅作备用
  • 第三方库如lxml支持etree.XPath和更灵活的命名空间处理,适合复杂场景