[Python] 一文看懂Python对XML文件序列化与反序列化解析教程(小白版)

729 0
Honkers 2026-1-24 15:05:19 来自手机 | 显示全部楼层 |阅读模式

一文看懂Python对XML文件序列化与反序列化解析教程(小白版)

前言

XML(可扩展标记语言)是一种广泛使用的数据交换格式,它具有良好的可读性和自我描述性。在Python开发中,我们经常需要处理XML数据,比如读取配置文件、交换数据等。本教程将详细介绍在Python中如何进行XML的序列化和反序列化操作,帮助小白快速掌握这一技能。

目录

  • 一、XML基础概念
  • 二、Python中处理XML的主要模块
  • 三、使用xml.etree.ElementTree
  • 四、简单XML的解析与生成
  • 五、包含列表的复杂XML
  • 六、嵌套XML的解析与生成
  • 七、使用minidom处理XML
  • 八、使用xmltodict简化XML处理
  • 九、对象和XML之间的序列化与反序列化
  • 十、实际应用场景
  • 十一、常见问题与解决方案
  • 十二、总结

一、XML基础概念

XML是一种标记语言,类似于HTML,但它设计用来传输和存储数据,而不是显示数据。XML的基本组成部分包括:

1. XML文档结构

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <root>
  3. <child attribute="value">内容</child>
  4. </root>
复制代码

2. XML的基本元素

  • 声明:如
  • 根元素:XML文档必须有一个根元素,如上面的
  • 元素:由开始标签和结束标签组成,如
  • 属性:提供元素的额外信息,如attribute="value"
  • 内容:元素中的文本,如上面的"内容"

二、Python中处理XML的主要模块

Python提供了多个处理XML的模块,主要包括:

  1. xml.etree.ElementTree:轻量级、快速的XML处理模块,Python标准库
  2. xml.dom.minidom:DOM(文档对象模型)风格的XML处理模块,Python标准库
  3. lxml:第三方库,功能更强大,性能更好,但需要单独安装
  4. xmltodict:第三方库,可以轻松地在XML和Python字典之间转换

本教程主要介绍Python标准库中的xml.etree.ElementTree和第三方库xmltodict,它们是最常用且易于上手的工具。

三、使用xml.etree.ElementTree

xml.etree.ElementTree模块提供了一个轻量级、高效的API,用于解析和创建XML数据。

1. 导入模块

首先,我们需要导入ElementTree模块:

  1. import xml.etree.ElementTree as ET
复制代码

2. ElementTree的基本概念

  • Element:表示XML中的一个元素
  • ElementTree:表示整个XML文档
  • 解析:将XML字符串或文件转换为ElementTree对象
  • 生成:将ElementTree或Element对象转换为XML字符串或写入文件

四、简单XML的解析与生成

让我们从最简单的例子开始,学习如何解析和生成简单的XML数据。

1. 解析简单XML

假设我们有一个名为person.xml的文件,内容如下:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <person>
  3. <name>张三</name>
  4. <age>30</age>
  5. <email>zhangsan@example.com</email>
  6. </person>
复制代码

以下是解析这个XML文件的代码:

  1. import xml.etree.ElementTree as ET
  2. # 解析XML文件
  3. tree = ET.parse('person.xml')
  4. # 获取根元素
  5. root = tree.getroot()
  6. # 打印根元素标签
  7. print(f"根元素标签: {root.tag}")
  8. # 遍历所有子元素
  9. for child in root:
  10. print(f"标签: {child.tag}, 文本: {child.text}")
  11. # 直接访问特定标签的内容
  12. name = root.find('name').text
  13. age = root.find('age').text
  14. email = root.find('email').text
  15. print(f"\n姓名: {name}")
  16. print(f"年龄: {age}")
  17. print(f"邮箱: {email}")
复制代码

运行结果:

  1. 根元素标签: person
  2. 标签: name, 文本: 张三
  3. 标签: age, 文本: 30
  4. 标签: email, 文本: zhangsan@example.com
  5. 姓名: 张三
  6. 年龄: 30
  7. 邮箱: zhangsan@example.com
复制代码

2. 生成简单XML

下面是创建上述XML文件的代码:

  1. import xml.etree.ElementTree as ET
  2. # 创建根元素
  3. person = ET.Element('person')
  4. # 创建子元素并添加文本
  5. name = ET.SubElement(person, 'name')
  6. name.text = '张三'
  7. age = ET.SubElement(person, 'age')
  8. age.text = '30'
  9. email = ET.SubElement(person, 'email')
  10. email.text = 'zhangsan@example.com'
  11. # 创建ElementTree对象
  12. tree = ET.ElementTree(person)
  13. # 写入XML文件
  14. tree.write('person.xml', encoding='UTF-8', xml_declaration=True)
  15. print("XML文件已成功创建!")
  16. # 也可以将XML转换为字符串输出
  17. xml_str = ET.tostring(person, encoding='UTF-8').decode('UTF-8')
  18. print("\n生成的XML内容:")
  19. print(xml_str)
复制代码

运行结果:

  1. XML文件已成功创建!
  2. 生成的XML内容:
  3. <person><name>张三</name><age>30</age><email>zhangsan@example.com</email></person>
复制代码

五、包含列表的复杂XML

接下来,我们学习如何处理包含列表的更复杂的XML结构。

1. 解析包含列表的XML

假设我们有一个名为classroom.xml的文件,内容如下:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <classroom>
  3. <class_name>高三(1)班</class_name>
  4. <teacher>王老师</teacher>
  5. <students>
  6. <student>
  7. <id>1</id>
  8. <name>张三</name>
  9. <age>18</age>
  10. </student>
  11. <student>
  12. <id>2</id>
  13. <name>李四</name>
  14. <age>17</age>
  15. </student>
  16. <student>
  17. <id>3</id>
  18. <name>王五</name>
  19. <age>18</age>
  20. </student>
  21. </students>
  22. </classroom>
复制代码

以下是解析这个XML文件的代码:

  1. import xml.etree.ElementTree as ET
  2. # 解析XML文件
  3. tree = ET.parse('classroom.xml')
  4. root = tree.getroot()
  5. # 获取班级基本信息
  6. class_name = root.find('class_name').text
  7. teacher = root.find('teacher').text
  8. print(f"班级: {class_name}")
  9. print(f"班主任: {teacher}")
  10. print("学生列表:")
  11. # 获取所有学生
  12. students = root.find('students')
  13. for student in students.findall('student'):
  14. id = student.find('id').text
  15. name = student.find('name').text
  16. age = student.find('age').text
  17. print(f" ID: {id}, 姓名: {name}, 年龄: {age}")
复制代码

运行结果:

  1. 班级: 高三(1)班
  2. 班主任: 王老师
  3. 学生列表:
  4. ID: 1, 姓名: 张三, 年龄: 18
  5. ID: 2, 姓名: 李四, 年龄: 17
  6. ID: 3, 姓名: 王五, 年龄: 18
复制代码

2. 生成包含列表的XML

下面是创建上述XML文件的代码:

  1. import xml.etree.ElementTree as ET
  2. # 创建根元素
  3. classroom = ET.Element('classroom')
  4. # 添加班级信息
  5. class_name = ET.SubElement(classroom, 'class_name')
  6. class_name.text = '高三(1)班'
  7. teacher = ET.SubElement(classroom, 'teacher')
  8. teacher.text = '王老师'
  9. # 创建学生列表元素
  10. students = ET.SubElement(classroom, 'students')
  11. # 添加第一个学生
  12. student1 = ET.SubElement(students, 'student')
  13. id1 = ET.SubElement(student1, 'id')
  14. id1.text = '1'
  15. name1 = ET.SubElement(student1, 'name')
  16. name1.text = '张三'
  17. age1 = ET.SubElement(student1, 'age')
  18. age1.text = '18'
  19. # 添加第二个学生
  20. student2 = ET.SubElement(students, 'student')
  21. id2 = ET.SubElement(student2, 'id')
  22. id2.text = '2'
  23. name2 = ET.SubElement(student2, 'name')
  24. name2.text = '李四'
  25. age2 = ET.SubElement(student2, 'age')
  26. age2.text = '17'
  27. # 添加第三个学生
  28. student3 = ET.SubElement(students, 'student')
  29. id3 = ET.SubElement(student3, 'id')
  30. id3.text = '3'
  31. name3 = ET.SubElement(student3, 'name')
  32. name3.text = '王五'
  33. age3 = ET.SubElement(student3, 'age')
  34. age3.text = '18'
  35. # 写入XML文件
  36. tree = ET.ElementTree(classroom)
  37. tree.write('classroom.xml', encoding='UTF-8', xml_declaration=True)
  38. print("XML文件已成功创建!")
复制代码

运行后会生成classroom.xml文件,内容与上面的示例相同。

六、嵌套XML的解析与生成

嵌套XML是指XML中包含复杂的层次结构。在Python中,我们可以通过嵌套的方式访问和创建这些结构。

1. 解析嵌套XML

假设我们有一个名为company.xml的文件,内容如下:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <company>
  3. <name>科技公司</name>
  4. <address>
  5. <street>科技园路100号</street>
  6. <city>深圳</city>
  7. <province>广东</province>
  8. <zipcode>518000</zipcode>
  9. </address>
  10. <departments>
  11. <department>
  12. <name>研发部</name>
  13. <manager>张经理</manager>
  14. <employees>
  15. <employee>
  16. <id>1001</id>
  17. <name>李四</name>
  18. <position>高级开发工程师</position>
  19. <contact>
  20. <phone>13800138001</phone>
  21. <email>lisi@example.com</email>
  22. </contact>
  23. </employee>
  24. <employee>
  25. <id>1002</id>
  26. <name>王五</name>
  27. <position>产品经理</position>
  28. <contact>
  29. <phone>13900139002</phone>
  30. <email>wangwu@example.com</email>
  31. </contact>
  32. </employee>
  33. </employees>
  34. </department>
  35. </departments>
  36. </company>
复制代码

以下是解析这个XML文件的代码:

  1. import xml.etree.ElementTree as ET
  2. # 解析XML文件
  3. tree = ET.parse('company.xml')
  4. root = tree.getroot()
  5. # 获取公司基本信息
  6. company_name = root.find('name').text
  7. print(f"公司名称: {company_name}")
  8. # 获取公司地址信息
  9. address = root.find('address')
  10. street = address.find('street').text
  11. city = address.find('city').text
  12. province = address.find('province').text
  13. zipcode = address.find('zipcode').text
  14. print(f"公司地址: {province}{city}{street},邮编: {zipcode}")
  15. # 获取部门信息
  16. print("部门信息:")
  17. departments = root.find('departments')
  18. for dept in departments.findall('department'):
  19. dept_name = dept.find('name').text
  20. manager = dept.find('manager').text
  21. print(f" 部门名称: {dept_name}")
  22. print(f" 部门经理: {manager}")
  23. print(f" 员工列表:")
  24. # 获取员工信息
  25. employees = dept.find('employees')
  26. for emp in employees.findall('employee'):
  27. emp_id = emp.find('id').text
  28. emp_name = emp.find('name').text
  29. position = emp.find('position').text
  30. # 获取员工联系方式
  31. contact = emp.find('contact')
  32. phone = contact.find('phone').text
  33. email = contact.find('email').text
  34. print(f" 员工ID: {emp_id}, 姓名: {emp_name}, 职位: {position}")
  35. print(f" 电话: {phone}, 邮箱: {email}")
复制代码

运行结果:

  1. 公司名称: 科技公司
  2. 公司地址: 广东深圳市科技园路100号,邮编: 518000
  3. 部门信息:
  4. 部门名称: 研发部
  5. 部门经理: 张经理
  6. 员工列表:
  7. 员工ID: 1001, 姓名: 李四, 职位: 高级开发工程师
  8. 电话: 13800138001, 邮箱: lisi@example.com
  9. 员工ID: 1002, 姓名: 王五, 职位: 产品经理
  10. 电话: 13900139002, 邮箱: wangwu@example.com
复制代码

2. 生成嵌套XML

下面是创建上述XML文件的代码:

  1. import xml.etree.ElementTree as ET
  2. # 创建根元素
  3. company = ET.Element('company')
  4. # 添加公司名称
  5. name = ET.SubElement(company, 'name')
  6. name.text = '科技公司'
  7. # 添加公司地址(嵌套结构)
  8. address = ET.SubElement(company, 'address')
  9. street = ET.SubElement(address, 'street')
  10. street.text = '科技园路100号'
  11. city = ET.SubElement(address, 'city')
  12. city.text = '深圳'
  13. province = ET.SubElement(address, 'province')
  14. province.text = '广东'
  15. zipcode = ET.SubElement(address, 'zipcode')
  16. zipcode.text = '518000'
  17. # 添加部门列表
  18. departments = ET.SubElement(company, 'departments')
  19. # 添加研发部
  20. dept = ET.SubElement(departments, 'department')
  21. dept_name = ET.SubElement(dept, 'name')
  22. dept_name.text = '研发部'
  23. dept_manager = ET.SubElement(dept, 'manager')
  24. dept_manager.text = '张经理'
  25. # 添加员工列表(嵌套结构)
  26. employees = ET.SubElement(dept, 'employees')
  27. # 添加第一个员工
  28. emp1 = ET.SubElement(employees, 'employee')
  29. emp1_id = ET.SubElement(emp1, 'id')
  30. emp1_id.text = '1001'
  31. emp1_name = ET.SubElement(emp1, 'name')
  32. emp1_name.text = '李四'
  33. emp1_pos = ET.SubElement(emp1, 'position')
  34. emp1_pos.text = '高级开发工程师'
  35. # 添加第一个员工的联系方式(嵌套结构)
  36. contact1 = ET.SubElement(emp1, 'contact')
  37. phone1 = ET.SubElement(contact1, 'phone')
  38. phone1.text = '13800138001'
  39. email1 = ET.SubElement(contact1, 'email')
  40. email1.text = 'lisi@example.com'
  41. # 添加第二个员工
  42. emp2 = ET.SubElement(employees, 'employee')
  43. emp2_id = ET.SubElement(emp2, 'id')
  44. emp2_id.text = '1002'
  45. emp2_name = ET.SubElement(emp2, 'name')
  46. emp2_name.text = '王五'
  47. emp2_pos = ET.SubElement(emp2, 'position')
  48. emp2_pos.text = '产品经理'
  49. # 添加第二个员工的联系方式(嵌套结构)
  50. contact2 = ET.SubElement(emp2, 'contact')
  51. phone2 = ET.SubElement(contact2, 'phone')
  52. phone2.text = '13900139002'
  53. email2 = ET.SubElement(contact2, 'email')
  54. email2.text = 'wangwu@example.com'
  55. # 写入XML文件
  56. tree = ET.ElementTree(company)
  57. tree.write('company.xml', encoding='UTF-8', xml_declaration=True)
  58. print("嵌套XML文件已成功创建!")
复制代码

运行后会生成company.xml文件,内容与上面的示例相同。

七、使用minidom处理XML

除了ElementTree,Python还提供了xml.dom.minidom模块,它实现了Document Object Model (DOM) API,可以用于处理XML数据。

1. 解析XML(使用minidom)

  1. from xml.dom import minidom
  2. # 解析XML文件
  3. doc = minidom.parse('person.xml')
  4. # 获取根元素
  5. root = doc.documentElement
  6. # 获取元素
  7. name = root.getElementsByTagName('name')[0].firstChild.data
  8. age = root.getElementsByTagName('age')[0].firstChild.data
  9. email = root.getElementsByTagName('email')[0].firstChild.data
  10. print(f"姓名: {name}")
  11. print(f"年龄: {age}")
  12. print(f"邮箱: {email}")
复制代码

运行结果:

  1. 姓名: 张三
  2. 年龄: 30
  3. 邮箱: zhangsan@example.com
复制代码

2. 生成XML(使用minidom)

  1. from xml.dom import minidom
  2. # 创建XML文档对象
  3. doc = minidom.Document()
  4. # 创建根元素
  5. person = doc.createElement('person')
  6. doc.appendChild(person)
  7. # 创建name元素
  8. name = doc.createElement('name')
  9. name_text = doc.createTextNode('张三')
  10. name.appendChild(name_text)
  11. person.appendChild(name)
  12. # 创建age元素
  13. age = doc.createElement('age')
  14. age_text = doc.createTextNode('30')
  15. age.appendChild(age_text)
  16. person.appendChild(age)
  17. # 创建email元素
  18. email = doc.createElement('email')
  19. email_text = doc.createTextNode('zhangsan@example.com')
  20. email.appendChild(email_text)
  21. person.appendChild(email)
  22. # 写入XML文件
  23. with open('person_minidom.xml', 'w', encoding='utf-8') as f:
  24. doc.writexml(f, addindent=' ', newl='\n', encoding='utf-8')
  25. print("使用minidom创建的XML文件已成功生成!")
复制代码

运行后会生成person_minidom.xml文件,内容与前面使用ElementTree生成的类似。

八、使用xmltodict简化XML处理

xmltodict是一个第三方库,它可以让我们像处理字典一样处理XML,使操作更加直观和简洁。

1. 安装xmltodict

首先,我们需要安装xmltodict库:

  1. pip install xmltodict
复制代码

2. 将XML转换为字典

  1. import xmltodict
  2. # 读取XML文件
  3. with open('person.xml', 'r', encoding='utf-8') as f:
  4. xml_string = f.read()
  5. # 将XML转换为字典
  6. person_dict = xmltodict.parse(xml_string)
  7. # 以字典方式访问数据
  8. print(f"姓名: {person_dict['person']['name']}")
  9. print(f"年龄: {person_dict['person']['age']}")
  10. print(f"邮箱: {person_dict['person']['email']}")
  11. # 打印完整字典
  12. print("\n完整字典数据:")
  13. print(person_dict)
复制代码

运行结果:

  1. 姓名: 张三
  2. 年龄: 30
  3. 邮箱: zhangsan@example.com
  4. 完整字典数据:
  5. OrderedDict([('person', OrderedDict([('name', '张三'), ('age', '30'), ('email', 'zhangsan@example.com')]))])
复制代码

3. 将字典转换为XML

  1. import xmltodict
  2. # 创建字典数据
  3. person_dict = {
  4. 'person': {
  5. 'name': '张三',
  6. 'age': '30',
  7. 'email': 'zhangsan@example.com'
  8. }
  9. }
  10. # 将字典转换为XML
  11. xml_string = xmltodict.unparse(person_dict, pretty=True)
  12. # 打印XML字符串
  13. print("生成的XML:")
  14. print(xml_string)
  15. # 保存到文件
  16. with open('person_xmltodict.xml', 'w', encoding='utf-8') as f:
  17. f.write(xml_string)
  18. print("\nXML文件已成功生成!")
复制代码

运行结果:

  1. 生成的XML:
  2. <?xml version="1.0" encoding="utf-8"?>
  3. <person>
  4. <name>张三</name>
  5. <age>30</age>
  6. <email>zhangsan@example.com</email>
  7. </person>
  8. XML文件已成功生成!
复制代码

九、对象和XML之间的序列化与反序列化

在实际开发中,我们经常需要在对象和XML之间进行转换,这就是所谓的序列化和反序列化。

1. 使用xml.etree.ElementTree实现对象序列化

下面是一个将Python对象序列化为XML的示例:

  1. import xml.etree.ElementTree as ET
  2. # 定义Person类
  3. class Person:
  4. def __init__(self, name, age, email):
  5. self.name = name
  6. self.age = age
  7. self.email = email
  8. # 序列化为XML
  9. def to_xml(self, file_path=None):
  10. # 创建根元素
  11. person = ET.Element('person')
  12. # 添加子元素
  13. name_elem = ET.SubElement(person, 'name')
  14. name_elem.text = self.name
  15. age_elem = ET.SubElement(person, 'age')
  16. age_elem.text = str(self.age)
  17. email_elem = ET.SubElement(person, 'email')
  18. email_elem.text = self.email
  19. # 如果提供了文件路径,则保存到文件
  20. if file_path:
  21. tree = ET.ElementTree(person)
  22. tree.write(file_path, encoding='UTF-8', xml_declaration=True)
  23. # 返回XML字符串
  24. return ET.tostring(person, encoding='UTF-8').decode('UTF-8')
  25. # 从XML反序列化
  26. @classmethod
  27. def from_xml(cls, xml_source):
  28. # 如果xml_source是字符串,解析为Element
  29. if isinstance(xml_source, str):
  30. # 如果是文件路径
  31. if xml_source.endswith('.xml'):
  32. tree = ET.parse(xml_source)
  33. root = tree.getroot()
  34. else: # 如果是XML字符串
  35. root = ET.fromstring(xml_source)
  36. else: # 如果已经是Element对象
  37. root = xml_source
  38. # 从Element中提取数据
  39. name = root.find('name').text
  40. age = int(root.find('age').text)
  41. email = root.find('email').text
  42. # 创建并返回Person对象
  43. return cls(name, age, email)
  44. # 测试序列化
  45. person = Person('张三', 30, 'zhangsan@example.com')
  46. xml_str = person.to_xml('person_obj.xml')
  47. print("序列化生成的XML:")
  48. print(xml_str)
  49. # 测试反序列化(从文件)
  50. person2 = Person.from_xml('person_obj.xml')
  51. print("\n从文件反序列化:")
  52. print(f"姓名: {person2.name}, 年龄: {person2.age}, 邮箱: {person2.email}")
  53. # 测试反序列化(从字符串)
  54. person3 = Person.from_xml(xml_str)
  55. print("\n从字符串反序列化:")
  56. print(f"姓名: {person3.name}, 年龄: {person3.age}, 邮箱: {person3.email}")
复制代码

运行结果:

  1. 序列化生成的XML:
  2. <person><name>张三</name><age>30</age><email>zhangsan@example.com</email></person>
  3. 从文件反序列化:
  4. 姓名: 张三, 年龄: 30, 邮箱: zhangsan@example.com
  5. 从字符串反序列化:
  6. 姓名: 张三, 年龄: 30, 邮箱: zhangsan@example.com
复制代码

2. 使用xmltodict实现对象序列化

下面是一个使用xmltodict实现对象序列化和反序列化的示例:

  1. import xmltodict
  2. # 定义Person类
  3. class Person:
  4. def __init__(self, name, age, email):
  5. self.name = name
  6. self.age = age
  7. self.email = email
  8. # 转换为字典
  9. def to_dict(self):
  10. return {
  11. 'person': {
  12. 'name': self.name,
  13. 'age': self.age,
  14. 'email': self.email
  15. }
  16. }
  17. # 序列化为XML
  18. def to_xml(self, file_path=None, pretty=True):
  19. xml_str = xmltodict.unparse(self.to_dict(), pretty=pretty)
  20. if file_path:
  21. with open(file_path, 'w', encoding='utf-8') as f:
  22. f.write(xml_str)
  23. return xml_str
  24. # 从XML反序列化
  25. @classmethod
  26. def from_xml(cls, xml_source):
  27. # 如果是文件路径
  28. if isinstance(xml_source, str) and xml_source.endswith('.xml'):
  29. with open(xml_source, 'r', encoding='utf-8') as f:
  30. xml_str = f.read()
  31. else:
  32. xml_str = xml_source
  33. # 解析XML为字典
  34. data_dict = xmltodict.parse(xml_str)
  35. # 提取数据
  36. person_data = data_dict['person']
  37. name = person_data['name']
  38. age = int(person_data['age']) # 转换为整数
  39. email = person_data['email']
  40. # 返回Person对象
  41. return cls(name, age, email)
  42. # 测试序列化
  43. person = Person('张三', 30, 'zhangsan@example.com')
  44. xml_str = person.to_xml('person_xmltodict_obj.xml')
  45. print("使用xmltodict序列化生成的XML:")
  46. print(xml_str)
  47. # 测试反序列化
  48. person2 = Person.from_xml('person_xmltodict_obj.xml')
  49. print("\n反序列化结果:")
  50. print(f"姓名: {person2.name}, 年龄: {person2.age}, 邮箱: {person2.email}")
复制代码

运行结果:

  1. 使用xmltodict序列化生成的XML:
  2. <?xml version="1.0" encoding="utf-8"?>
  3. <person>
  4. <name>张三</name>
  5. <age>30</age>
  6. <email>zhangsan@example.com</email>
  7. </person>
  8. 反序列化结果:
  9. 姓名: 张三, 年龄: 30, 邮箱: zhangsan@example.com
复制代码

十、实际应用场景

1. 配置文件读写

XML常被用作应用程序的配置文件格式。下面是一个读写配置文件的示例:

  1. import xml.etree.ElementTree as ET
  2. class ConfigManager:
  3. def __init__(self):
  4. self.config = None
  5. # 从文件加载配置
  6. def load_config(self, file_path):
  7. tree = ET.parse(file_path)
  8. self.config = tree.getroot()
  9. return self.config
  10. # 获取配置项
  11. def get_value(self, *path):
  12. if not self.config:
  13. raise ValueError("配置未加载")
  14. element = self.config
  15. for tag in path:
  16. element = element.find(tag)
  17. if element is None:
  18. return None
  19. return element.text
  20. # 设置配置项
  21. def set_value(self, value, *path):
  22. if not self.config:
  23. raise ValueError("配置未加载")
  24. element = self.config
  25. # 查找或创建路径上的元素
  26. for tag in path[:-1]:
  27. next_element = element.find(tag)
  28. if next_element is None:
  29. next_element = ET.SubElement(element, tag)
  30. element = next_element
  31. # 设置最终元素的值
  32. final_tag = path[-1]
  33. final_element = element.find(final_tag)
  34. if final_element is None:
  35. final_element = ET.SubElement(element, final_tag)
  36. final_element.text = str(value)
  37. # 保存配置到文件
  38. def save_config(self, file_path):
  39. if not self.config:
  40. raise ValueError("配置未加载")
  41. tree = ET.ElementTree(self.config)
  42. tree.write(file_path, encoding='UTF-8', xml_declaration=True)
  43. # 创建默认配置文件
  44. def create_default_config(file_path):
  45. # 创建根元素
  46. app_config = ET.Element('AppConfig')
  47. # 添加应用基本信息
  48. app = ET.SubElement(app_config, 'App')
  49. name = ET.SubElement(app, 'Name')
  50. name.text = 'MyApplication'
  51. version = ET.SubElement(app, 'Version')
  52. version.text = '1.0.0'
  53. debug = ET.SubElement(app, 'Debug')
  54. debug.text = 'true'
  55. # 添加数据库配置
  56. db = ET.SubElement(app_config, 'Database')
  57. provider = ET.SubElement(db, 'Provider')
  58. provider.text = 'SQLite'
  59. connection = ET.SubElement(db, 'ConnectionString')
  60. connection.text = 'Data Source=app.db'
  61. max_conn = ET.SubElement(db, 'MaxConnections')
  62. max_conn.text = '10'
  63. # 保存到文件
  64. tree = ET.ElementTree(app_config)
  65. tree.write(file_path, encoding='UTF-8', xml_declaration=True)
  66. print(f"默认配置文件已创建: {file_path}")
  67. # 测试代码
  68. config_path = 'app_config.xml'
  69. # 创建默认配置
  70. create_default_config(config_path)
  71. # 使用配置管理器
  72. manager = ConfigManager()
  73. manager.load_config(config_path)
  74. # 读取配置
  75. app_name = manager.get_value('App', 'Name')
  76. app_version = manager.get_value('App', 'Version')
  77. db_provider = manager.get_value('Database', 'Provider')
  78. print(f"应用名称: {app_name}")
  79. print(f"应用版本: {app_version}")
  80. print(f"数据库提供商: {db_provider}")
  81. # 修改配置
  82. manager.set_value('1.1.0', 'App', 'Version')
  83. manager.set_value('20', 'Database', 'MaxConnections')
  84. manager.save_config(config_path)
  85. print("配置已更新")
  86. # 重新加载配置
  87. manager.load_config(config_path)
  88. print(f"新的应用版本: {manager.get_value('App', 'Version')}")
  89. print(f"新的最大连接数: {manager.get_value('Database', 'MaxConnections')}")
复制代码

运行结果:

  1. 默认配置文件已创建: app_config.xml
  2. 应用名称: MyApplication
  3. 应用版本: 1.0.0
  4. 数据库提供商: SQLite
  5. 配置已更新
  6. 新的应用版本: 1.1.0
  7. 新的最大连接数: 20
复制代码

2. 数据交换

在不同系统之间交换数据时,XML是一种常用的格式。下面是一个简单的数据交换示例:

  1. import xml.etree.ElementTree as ET
  2. import xmltodict
  3. # 模拟从外部系统接收的XML数据
  4. def receive_data_from_external_system():
  5. return '''<?xml version="1.0" encoding="UTF-8"?>
  6. <order>
  7. <order_id>ORD-2023-0001</order_id>
  8. <customer>
  9. <name>张三</name>
  10. <email>zhangsan@example.com</email>
  11. <phone>13800138000</phone>
  12. </customer>
  13. <items>
  14. <item>
  15. <product_id>101</product_id>
  16. <name>笔记本电脑</name>
  17. <quantity>1</quantity>
  18. <price>5999.99</price>
  19. </item>
  20. <item>
  21. <product_id>102</product_id>
  22. <name>无线鼠标</name>
  23. <quantity>2</quantity>
  24. <price>99.99</price>
  25. </item>
  26. </items>
  27. <order_date>2023-06-15</order_date>
  28. <total_amount>6199.97</total_amount>
  29. </order>'''
  30. # 解析接收到的XML数据
  31. def process_order_xml(xml_string):
  32. # 使用ElementTree解析
  33. root = ET.fromstring(xml_string)
  34. # 提取订单信息
  35. order_id = root.find('order_id').text
  36. order_date = root.find('order_date').text
  37. total_amount = root.find('total_amount').text
  38. # 提取客户信息
  39. customer = root.find('customer')
  40. customer_name = customer.find('name').text
  41. customer_email = customer.find('email').text
  42. customer_phone = customer.find('phone').text
  43. print(f"订单编号: {order_id}")
  44. print(f"订单日期: {order_date}")
  45. print(f"订单总额: ¥{total_amount}")
  46. print(f"客户信息: {customer_name} ({customer_email}, {customer_phone})")
  47. print("订单明细:")
  48. # 提取订单商品
  49. items = root.find('items')
  50. for item in items.findall('item'):
  51. product_id = item.find('product_id').text
  52. product_name = item.find('name').text
  53. quantity = item.find('quantity').text
  54. price = item.find('price').text
  55. print(f" - {product_name} (ID: {product_id}): {quantity} x ¥{price} = ¥{float(quantity) * float(price)}")
  56. # 使用xmltodict解析为字典,便于进一步处理
  57. order_dict = xmltodict.parse(xml_string)
  58. return order_dict
  59. # 生成响应XML
  60. def generate_response_xml(order_dict, status="success", message="订单处理成功"):
  61. # 创建响应字典
  62. response_dict = {
  63. 'response': {
  64. 'order_id': order_dict['order']['order_id'],
  65. 'status': status,
  66. 'message': message,
  67. 'timestamp': '2023-06-15T10:30:00Z'
  68. }
  69. }
  70. # 转换为XML
  71. xml_response = xmltodict.unparse(response_dict, pretty=True)
  72. return xml_response
  73. # 测试数据交换流程
  74. xml_data = receive_data_from_external_system()
  75. print("接收到的XML数据:")
  76. print(xml_data[:200] + "...") # 只显示部分XML
  77. print("\n处理结果:")
  78. # 处理数据
  79. order_dict = process_order_xml(xml_data)
  80. # 生成响应
  81. response_xml = generate_response_xml(order_dict)
  82. print("\n生成的响应XML:")
  83. print(response_xml)
复制代码

运行结果:

  1. 接收到的XML数据:
  2. <?xml version="1.0" encoding="UTF-8"?>
  3. <order>
  4. <order_id>ORD-2023-0001</order_id>
  5. <customer>
  6. <name>张三</name>
  7. <email>zhangsan@example.com</email>
  8. <phone>13800138000</phone>
  9. </customer>...
  10. 处理结果:
  11. 订单编号: ORD-2023-0001
  12. 订单日期: 2023-06-15
  13. 订单总额: ¥6199.97
  14. 客户信息: 张三 (zhangsan@example.com, 13800138000)
  15. 订单明细:
  16. - 笔记本电脑 (ID: 101): 1 x ¥5999.99 = ¥5999.99
  17. - 无线鼠标 (ID: 102): 2 x ¥99.99 = ¥199.98
  18. 生成的响应XML:
  19. <?xml version="1.0" encoding="utf-8"?>
  20. <response>
  21. <order_id>ORD-2023-0001</order_id>
  22. <status>success</status>
  23. <message>订单处理成功</message>
  24. <timestamp>2023-06-15T10:30:00Z</timestamp>
  25. </response>
复制代码

十一、常见问题与解决方案

1. 中文乱码问题

问题:处理包含中文的XML文件时,出现乱码。

解决方案:在读写XML文件时,显式指定编码为UTF-8。

  1. import xml.etree.ElementTree as ET
  2. # 正确写入带中文的XML文件
  3. def write_xml_with_utf8(element, file_path):
  4. tree = ET.ElementTree(element)
  5. # 显式指定编码为UTF-8
  6. tree.write(file_path, encoding='UTF-8', xml_declaration=True)
  7. # 正确读取带中文的XML文件
  8. def read_xml_with_utf8(file_path):
  9. # ElementTree默认支持UTF-8
  10. tree = ET.parse(file_path)
  11. return tree.getroot()
复制代码

2. 解析不规范的XML

问题:处理一些不规范的XML(如没有结束标签、大小写不匹配等)。

解决方案:可以使用lxml库的recover选项,它能够处理一些不规范的XML。

首先安装lxml:

  1. pip install lxml
复制代码

然后使用lxml解析不规范的XML:

  1. from lxml import etree
  2. def parse_non_standard_xml(xml_string):
  3. # 使用lxml的HTML解析器,它更宽松,能够处理不规范的XML
  4. parser = etree.HTMLParser(recover=True)
  5. tree = etree.fromstring(xml_string, parser)
  6. return tree
  7. # 示例:解析缺少结束标签的XML
  8. bad_xml = '<root><item>1<item>2</root>'
  9. tree = parse_non_standard_xml(bad_xml)
  10. print("成功解析不规范的XML")
复制代码

3. 处理大型XML文件

问题:直接解析大型XML文件会占用过多内存。

解决方案:使用ElementTree的迭代解析功能或SAX(Simple API for XML)解析器。

  1. import xml.etree.ElementTree as ET
  2. def parse_large_xml(file_path, tag_to_extract):
  3. """迭代解析大型XML文件"""
  4. context = ET.iterparse(file_path, events=('start', 'end'))
  5. # 获取根元素
  6. event, root = next(context)
  7. for event, elem in context:
  8. if event == 'end' and elem.tag == tag_to_extract:
  9. # 处理元素
  10. yield elem
  11. # 清理已处理的元素,释放内存
  12. root.clear()
  13. # 示例:迭代解析大型XML文件中的所有<item>元素
  14. for item in parse_large_xml('large_file.xml', 'item'):
  15. # 处理每个item元素
  16. print(f"处理元素: {item.tag}")
复制代码

4. XML命名空间处理

问题:XML中包含命名空间,导致无法直接通过标签名查找元素。

解决方案:在查找元素时指定命名空间。

  1. import xml.etree.ElementTree as ET
  2. # 包含命名空间的XML示例
  3. xml_with_ns = '''<?xml version="1.0" encoding="UTF-8"?>
  4. <root xmlns:data="http://example.org/data">
  5. <data:person>
  6. <data:name>张三</data:name>
  7. <data:age>30</data:age>
  8. </data:person>
  9. </root>'''
  10. # 解析包含命名空间的XML
  11. root = ET.fromstring(xml_with_ns)
  12. # 定义命名空间字典
  13. namespaces = {'data': 'http://example.org/data'}
  14. # 使用命名空间查找元素
  15. person = root.find('data:person', namespaces)
  16. name = person.find('data:name', namespaces).text
  17. age = person.find('data:age', namespaces).text
  18. print(f"姓名: {name}, 年龄: {age}")
复制代码

运行结果:

  1. 姓名: 张三, 年龄: 30
复制代码

5. 添加和修改XML属性

问题:需要在XML元素中添加或修改属性。

解决方案:使用Element的set方法设置属性。

  1. import xml.etree.ElementTree as ET
  2. # 创建根元素
  3. person = ET.Element('person')
  4. # 添加属性
  5. person.set('id', '1001')
  6. person.set('status', 'active')
  7. # 添加子元素
  8. name = ET.SubElement(person, 'name')
  9. name.text = '张三'
  10. # 修改属性
  11. person.set('status', 'inactive')
  12. # 获取属性值
  13. id_value = person.get('id')
  14. status_value = person.get('status')
  15. print(f"元素属性 - ID: {id_value}, 状态: {status_value}")
复制代码

运行结果:

  1. 元素属性 - ID: 1001, 状态: inactive
复制代码

十二、总结

通过本教程,我们学习了在Python中处理XML的各种方法:

  1. 基本概念:了解了XML的基本结构和Python中处理XML的主要模块
  2. 使用ElementTree:学习了如何使用ElementTree解析和生成XML
  3. 使用minidom:了解了如何使用minidom处理XML
  4. 使用xmltodict:学习了如何使用xmltodict在XML和字典之间转换
  5. 对象序列化:学习了如何在Python对象和XML之间进行序列化和反序列化
  6. 实际应用场景:了解了XML在配置文件和数据交换中的应用
  7. 常见问题解决方案:学习了如何处理中文乱码、不规范XML、大型XML文件等问题

Python提供了多种处理XML的方式,可以根据具体需求选择合适的方法。ElementTree是Python标准库中推荐的方式,简单易用;而xmltodict则提供了更直观的字典式访问方式,适合快速开发。

希望本教程能够帮助你快速掌握Python中XML的处理技巧,在实际项目中灵活运用。

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2026 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行