Python轮子:xml文件解析利器

原文链接:http://www.juzicode.com/python-module-xml/

XML(可扩展标记语言)是一种基于文本的标记语言,拥有自定义标签、树状结构、严格语法(区分大小写、标签闭合)及高可读性等特点。其设计注重数据内容与格式分离,支持跨平台和扩展性,适用于异构系统间的结构化数据交换。主要用途涵盖配置文件(如软件设置)、数据传输(如Web服务、RSS)、文档存储(如Office文件格式)及标准化数据共享,凭借独立于软硬件的特性,成为通用数据描述与交换的核心工具。

xml模块是Python标准库中用于处理 XML 数据的模块,提供解析、生成和修改 XML 文档的功能。支持 DOM 和 SAX 解析模式,适用于配置文件处理、数据交换和 Web 服务等场景。

应用场景

  • 配置文件:读写 XML 格式的系统配置
  • 数据交换:处理 SOAP/RSS 等 XML 协议数据
  • 文档处理:生成符合行业标准的 XML 文档
  • Web 服务:解析 API 返回的 XML 响应

安装或导入

Python的内置标准库,直接导入使用:

import xml.etree.ElementTree as ET

基本用法

以下示例展示 XML 文档的解析、创建等基础操作。

1. 解析 XML 文件

使用 ElementTree 解析 XML 文件并遍历元素。parse() 方法加载文件,iter() 遍历节点。

#juzicode.com/VX公众号:juzicode
import xml.etree.ElementTree as ET

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

for child in root:
    print(f"Tag: {child.tag}, Attr: {child.attrib}")

data.xml 内容为:

<root>
  <item id="1">A</item>
  <item id="2">B</item>
</root>

运行结果:

Tag: item, Attr: {'id': '1'}
Tag: item, Attr: {'id': '2'}

2. 创建 XML 文档

通过 Element 和 SubElement 构建 XML 结构。ET.Element() 创建根节点,ET.dump() 输出文档。

#juzicode.com/VX公众号:juzicode
import xml.etree.ElementTree as ET

root = ET.Element("catalog")
book = ET.SubElement(root, "book", id="bk101")
title = ET.SubElement(book, "title")
title.text = "Python Guide"
ET.dump(root)

运行结果:

<catalog>
  <book id="bk101">
    <title>Python Guide</title>
  </book>
</catalog>

3. 修改 XML 内容

定位元素并修改属性与文本。find() 方法查找子元素,set() 修改属性。

#juzicode.com/VX公众号:juzicode
import xml.etree.ElementTree as ET

root = ET.fromstring('<item><name>Old</name></item>')
name = root.find('name')
name.text = "New"
name.set('updated', 'true')
ET.dump(root)

运行结果:

<item>
  <name updated="true">New</name>
</item>

4. 查找元素

使用 XPath 表达式查询元素。findall() 支持 XPath 语法定位节点。

#juzicode.com/VX公众号:juzicode
import xml.etree.ElementTree as ET

xml_data = '''
<users>
  <user role="admin">Alice</user>
  <user role="user">Bob</user>
</users>
'''
root = ET.fromstring(xml_data)
admins = root.findall(".//user[@role='admin']")
print([elem.text for elem in admins])

运行结果:

['Alice']

5. 写入 XML 文件

将内存中的 XML 树写入文件。ElementTree.write() 方法实现持久化存储。

#juzicode.com/VX公众号:juzicode
import xml.etree.ElementTree as ET

root = ET.Element("config")
ET.SubElement(root, "entry", key="lang").text = "Python"
tree = ET.ElementTree(root)
tree.write("output.xml", encoding="utf-8", xml_declaration=True)

生成文件内容:

<?xml version='1.0' encoding='utf-8'?>
<config>
  <entry key="lang">Python</entry>
</config>

6. 处理 XML 命名空间

注册命名空间并解析带前缀的 XML。使用 register_namespace() 避免前缀冲突。

#juzicode.com/VX公众号:juzicode
import xml.etree.ElementTree as ET

ET.register_namespace('ns', 'http://juzicode.com')
xml_data = '''
<ns:root xmlns:ns="http://juzicode.com">
  <ns:item>Test</ns:item>
</ns:root>
'''
root = ET.fromstring(xml_data)
item = root.find('ns:item', {'ns': 'http://juzicode.com'})
print(item.text)

运行结果:

Test

高级功能

以下示例展示 XML 处理的进阶用法,可以处理一些复杂数据结构、满足性能需求。

1. SAX 解析大文件

使用 SAX 解析器处理大型 XML 文件。通过事件驱动模型节省内存。

#juzicode.com/VX公众号:juzicode
import xml.sax

class MyHandler(xml.sax.ContentHandler):
    def startElement(self, name, attrs):
        print(f"Start: {name}")
    
parser = xml.sax.make_parser()
parser.setContentHandler(MyHandler())
parser.parse("big.xml")

big .xml 内容为:

<?xml version='1.0' encoding='UTF-8'?>
<data>
    <item>Content 1</item>
    <item>Content 2</item>
    <item>Content 3</item>
    <metadata>
        <author>XML Generator</author>
    </metadata>
    <item>Content 4</item>
    <item>Content 5</item>
</data>

运行结果:

Start: data
Start: item
Start: item
Start: item
Start: metadata
Start: author
Start: item
Start: item

2. 生成 CDATA 段

通过扩展函数生成 CDATA 内容。自定义 Element 的子类处理特殊标记。

#juzicode.com/VX公众号:juzicode
def CDATA(text):
    element = ET.Element('![CDATA[')
    element.text = text
    return element

root = ET.Element("data")
root.append(CDATA("特殊内容 & 符号"))
ET.dump(root)

运行结果:

<data>
  <![CDATA[特殊内容 & 符号]]>
</data>

3. 流式解析大文件

使用 iterparse 增量解析 XML 文件。及时清除已处理元素节省内存。

#juzicode.com/VX公众号:juzicode
import xml.etree.ElementTree as ET

for event, elem in ET.iterparse("big.xml", events=("start", "end")):
    if event == "end" and elem.tag == "item":
        print(elem.text)
        elem.clear()

big .xml 内容为:

<?xml version='1.0' encoding='UTF-8'?>
<data>
    <item>Content 1</item>
    <item>Content 2</item>
    <item>Content 3</item>
    <metadata>
        <author>XML Generator</author>
    </metadata>
    <item>Content 4</item>
    <item>Content 5</item>
</data>

运行结果:

Content 1
Content 2
Content 3
Content 4
Content 5

4. 转换 XML 到字典

递归遍历 XML 节点生成 Python 字典。适用于将 XML 数据转换为 JSON 格式。

#juzicode.com/VX公众号:juzicode
def xml_to_dict(element):
    return {
        **element.attrib,
        "text": element.text,
        "children": [xml_to_dict(child) for child in element]
    }

root = ET.fromstring('<root><item id="1">A</item></root>')
print(xml_to_dict(root))

运行结果:

{
    "text": None,
    "children": [{
        "id": "1",
        "text": "A",
        "children": []
    }]
}

总结

xml 模块支持 DOM 和 SAX 两种解析模式,具有完整的 XML 标准兼容性、灵活的内存与性能平衡方案。该模块是处理 XML 数据的瑞士军刀,通过合理选择解析模式和扩展方法,可以应对从简单配置到企业级数据交换的各种需求。

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注