Python3 XML 解析(详细教程)

Python3 XML 解析:从零开始掌握结构化数据处理

在现代软件开发中,XML(可扩展标记语言)是一种非常常见的数据交换格式。它以文本形式存储结构化信息,广泛用于配置文件、API 接口响应、数据导出等场景。对于 Python 开发者而言,掌握 Python3 XML 解析 技术,是处理这类数据的基础能力之一。

想象一下,你正在开发一个电商系统,需要读取来自第三方平台的订单信息。这些信息以 XML 格式返回,包含商品名称、数量、价格等字段。如果没有合适的解析工具,你就得手动拆分字符串,既低效又容易出错。而 Python 内置的 xml 模块,就像一把精准的瑞士军刀,能帮你轻松完成这项任务。

本文将带你从基础语法到实战应用,系统学习如何使用 Python3 对 XML 数据进行读取、遍历和提取,适合编程初学者和中级开发者。


XML 基础结构与 Python3 解析的准备

在开始解析之前,先了解 XML 的基本结构。一个典型的 XML 文件看起来像这样:

<?xml version="1.0" encoding="UTF-8"?>
<orders>
    <order id="1001">
        <customer>张三</customer>
        <product>笔记本电脑</product>
        <quantity>1</quantity>
        <price>6999.00</price>
    </order>
    <order id="1002">
        <customer>李四</customer>
        <product>无线鼠标</product>
        <quantity>2</quantity>
        <price>129.00</price>
    </order>
</orders>

这段代码中:

  • <?xml version="1.0" encoding="UTF-8"?> 是 XML 声明,告诉解析器编码方式。
  • <orders> 是根元素,包含所有订单数据。
  • <order> 是子元素,每个代表一个订单,带有 id 属性。
  • 内部的 <customer><product> 等是标签,包含具体值。

Python3 提供了多种方式解析 XML,最常用的是 xml.etree.ElementTree 模块,简称 ET。它轻量、高效,是官方推荐的标准库。


使用 ElementTree 进行 XML 解析

ElementTree 是 Python3 中最常用、最易上手的 XML 解析方式。它将 XML 文件转换为树状结构,每个节点都是一个 Element 对象,你可以像操作树一样遍历和提取数据。

下面是一个完整的解析示例:

import xml.etree.ElementTree as ET

tree = ET.parse('orders.xml')  # 解析文件,返回一个 Tree 对象

root = tree.getroot()

for order in root.findall('order'):
    order_id = order.get('id')  # 获取 id 属性
    customer = order.find('customer').text  # 获取 <customer> 的文本内容
    product = order.find('product').text
    quantity = int(order.find('quantity').text)
    price = float(order.find('price').text)
    
    # 打印每条订单信息
    print(f"订单 ID: {order_id}, 客户: {customer}, 商品: {product}, 数量: {quantity}, 价格: {price}")

代码注释说明

  • ET.parse('orders.xml'):从本地文件加载 XML 数据,构建解析树。
  • getroot():获取根元素,是所有数据的入口。
  • findall('order'):查找所有名为 order 的子元素,返回列表。
  • get('id'):从元素中提取属性值,注意不是 text
  • find('customer'):查找第一个子标签,返回 Element 对象。
  • .text:获取标签内的文本内容,如 “张三”。

运行这段代码,你会看到类似输出:

订单 ID: 1001, 客户: 张三, 商品: 笔记本电脑, 数量: 1, 价格: 6999.0
订单 ID: 1002, 客户: 李四, 商品: 无线鼠标, 数量: 2, 价格: 129.0

处理嵌套结构与属性值提取

现实中的 XML 数据往往更复杂,存在多层嵌套。例如,一个订单可能包含多个商品明细。我们来看一个更复杂的例子:

<?xml version="1.0" encoding="UTF-8"?>
<store>
    <branch name="北京朝阳店">
        <product id="p001">
            <name>苹果</name>
            <price>5.5</price>
            <stock>100</stock>
        </product>
        <product id="p002">
            <name>香蕉</name>
            <price>3.8</price>
            <stock>150</stock>
        </product>
    </branch>
    <branch name="上海浦东店">
        <product id="p003">
            <name>橙子</name>
            <price>6.0</price>
            <stock>80</stock>
        </product>
    </branch>
</store>

解析这种结构时,我们需要逐层访问:

import xml.etree.ElementTree as ET

tree = ET.parse('store.xml')
root = tree.getroot()

for branch in root.findall('branch'):
    branch_name = branch.get('name')  # 获取 branch 的 name 属性
    print(f"分店: {branch_name}")

    # 遍历该分店内的所有 product
    for product in branch.findall('product'):
        product_id = product.get('id')
        name = product.find('name').text
        price = float(product.find('price').text)
        stock = int(product.find('stock').text)
        
        print(f"  商品 ID: {product_id}, 名称: {name}, 价格: {price}, 库存: {stock}")

输出结果:

分店: 北京朝阳店
  商品 ID: p001, 名称: 苹果, 价格: 5.5, 库存: 100
  商品 ID: p002, 名称: 香蕉, 价格: 3.8, 库存: 150
分店: 上海浦东店
  商品 ID: p003, 名称: 橙子, 价格: 6.0, 库存: 80

关键技巧

  • findall()find() 的路径表达式支持层级关系,如 branch/product
  • 属性通过 .get('属性名') 获取,不能用 .text
  • 嵌套结构用多层 for 循环遍历,逻辑清晰。

使用 XML 字符串直接解析

除了读取文件,你也可以直接解析 XML 字符串,这在处理 API 响应时非常实用。例如,从 HTTP 接口获取的 XML 数据:

import xml.etree.ElementTree as ET

xml_data = '''
<weather>
    <city>上海</city>
    <temperature unit="摄氏度">23</temperature>
    <status>多云</status>
    <humidity>65%</humidity>
</weather>
'''

root = ET.fromstring(xml_data)

city = root.find('city').text
temp = root.find('temperature').text
unit = root.find('temperature').get('unit')
status = root.find('status').text
humidity = root.find('humidity').text

print(f"城市: {city}")
print(f"温度: {temp} {unit}")
print(f"天气: {status}")
print(f"湿度: {humidity}")

输出:

城市: 上海
温度: 23 摄氏度
天气: 多云
湿度: 65%

使用场景

  • 从网络请求中获取 XML 数据后,无需保存文件即可解析。
  • 适合快速测试或数据校验。

错误处理与健壮性提升

在真实项目中,XML 数据可能格式错误或缺少字段。因此,添加异常处理是必要的。

import xml.etree.ElementTree as ET

def parse_orders(file_path):
    try:
        tree = ET.parse(file_path)
        root = tree.getroot()
    except ET.ParseError as e:
        print(f"XML 解析失败: {e}")
        return
    except FileNotFoundError:
        print(f"文件未找到: {file_path}")
        return

    for order in root.findall('order'):
        order_id = order.get('id') or "未知"
        customer = order.find('customer')
        product = order.find('product')
        quantity = order.find('quantity')
        price = order.find('price')

        # 检查元素是否存在
        customer_text = customer.text if customer is not None else "无"
        product_text = product.text if product is not None else "无"
        qty = int(quantity.text) if quantity is not None and quantity.text else 0
        prc = float(price.text) if price is not None and price.text else 0.0

        print(f"订单 ID: {order_id}, 客户: {customer_text}, 商品: {product_text}, 数量: {qty}, 价格: {prc}")

健壮性设计要点

  • 使用 try-except 捕获 ParseErrorFileNotFoundError
  • 对每个 find() 结果判断是否为 None,避免 AttributeError。
  • 使用默认值(如 or "未知")防止空值崩溃。

实际应用场景与建议

Python3 XML 解析 的应用场景非常广泛,例如:

  • 解析配置文件(如 Django 的 settings.xml)。
  • 处理 RSS 订阅源(XML 格式)。
  • 与旧系统对接,接收 XML 数据接口。
  • 数据迁移工具中读取历史 XML 导出文件。

建议

  • 对于简单 XML,优先使用 ElementTree
  • 若需处理超大文件(GB 级),考虑使用 xml.sax 流式解析,内存占用更低。
  • 避免手动字符串处理,效率低且易错。

总结与进阶方向

掌握 Python3 XML 解析,不仅能让你高效处理结构化数据,还能提升你在系统集成、数据清洗等任务中的竞争力。从基础的 parse()find(),到嵌套结构遍历、错误处理,再到字符串解析,这些技能构成了完整的处理链路。

建议你在学习后尝试:

  • 将一个 XML 文件转换为 JSON 格式。
  • 编写一个通用的 XML 解析器类,封装常用方法。
  • 使用 lxml 库(第三方)学习 XPath 表达式,实现更复杂的查询。

编程的本质是解决问题。当你能熟练运用 Python3 解析 XML,就等于为自己的工具箱添了一件利器。坚持练习,你会发现,复杂的数据结构,也能被你轻松拆解。