# -*- coding: utf-8 -*-
"""
Created on Fri May 5 14:11:22 2023
@author: Administrator
来源:https://docs.python.org/zh-cn/3/library/xml.etree.elementtree.html#xml-tree-and-elements
xml.etree.ElementTree 模块实现了一个简单高效的API,用于解析和创建XML数据。
"""
# 从文件中读取来导入此数据
import xml.etree.ElementTree as ET
tree = ET.parse('data/country_data.xml')
root = tree.getroot()
# # 或直接从字符串中解析
# country_data_as_string = """<?xml version="1.0"?>
# <data>
# <country name="Liechtenstein">
# <rank>1</rank>
# <year>2008</year>
# <gdppc>141100</gdppc>
# <neighbor name="Austria" direction="E"/>
# <neighbor name="Switzerland" direction="W"/>
# </country>
# <country name="Singapore">
# <rank>4</rank>
# <year>2011</year>
# <gdppc>59900</gdppc>
# <neighbor name="Malaysia" direction="N"/>
# </country>
# <country name="Panama">
# <rank>68</rank>
# <year>2011</year>
# <gdppc>13600</gdppc>
# <neighbor name="Costa Rica" direction="W"/>
# <neighbor name="Colombia" direction="E"/>
# </country>
# </data> """
# root = ET.fromstring(country_data_as_string)
# fromstring() 将 XML 从字符串直接解析为 Element
# 作为 Element , root 具有标签和属性字典
root.tag
# 可以迭代的子节点
for child in root:
print(child.tag,child.attrib)
# 子级可以嵌套的,可以通过索引访问特定的子级节点
root[0][1].text
# 可以使用 XMLParser 并以增量方式添加数据
# 针对此需求的最强大工具是 XMLPullParser。 它不要求通过阻塞式读取来获得 XML 数据,而是通过执行 XMLPullParser.feed() 调用来增量式地添加数据。 要获得已解析的 XML 元素,应调用 XMLPullParser.read_events()
parser = ET.XMLPullParser(['start', 'end'])
parser.feed('<mytag>sometext')
list(parser.read_events())
parser.feed(' more text</mytag>')
for event, elem in parser.read_events():
print(event)
print(elem.tag, 'text=', elem.text)
# =============================================================================
# # 查找感兴趣的元素
# =============================================================================
# Element.iter() 递归遍历其下的所有子树(包括子级,子级的子级,等等)
for neighbor in root.iter('neighbor'):
print(neighbor.attrib)
# Element.findall() 仅查找当前元素的直接子元素中带有指定标签的元素
# Element.find() 找带有特定标签的第一个子级,然后可以用 Element.text 访问元素的文本内容
# Element.get 访问元素的属性
for country in root.findall('country'):
rank = country.find('rank').text
name = country.get('name')
print(name, rank)
# =============================================================================
# # 通过使用 XPath ,可以更精确地指定要查找的元素。
# =============================================================================
# Top-level elements
root.findall(".")
# All 'neighbor' grand-children of 'country' children of the top-level
# elements
root.findall("./country/neighbor")
# Nodes with name='Singapore' that have a 'year' child
root.findall(".//year/..[@name='Singapore']")
# 'year' nodes that are children of nodes with name='Singapore'
root.findall(".//*[@name='Singapore']/year")
# All 'neighbor' nodes that are the second child of their parent
root.findall(".//neighbor[2]")
# 对于带有命名空间的 XML,应使用通常的限定 {namespace}tag 标记法
# All dublin-core "title" tags in the document
root.findall(".//{http://purl.org/dc/elements/1.1/}title")
# =============================================================================
# # 修改XML文件
# =============================================================================
# 调用 ElementTree.write() 可将xml文档写入文件。
# 使用 Element.text 修改文本字段,
# 使用 Element.set() 方法添加和修改属性,
# 使用 Element.append() 添加新的子元素。
# 假设我们要为每个国家/地区的中添加一个排名,并在排名元素中添加一个 updated 属性
for rank in root.iter('rank'):
new_rank = int(rank.text) + 1
rank.text = str(new_rank)
rank.set('updated', 'yes')
tree.write(r'data/output.xml')
# 使用 Element.remove() 删除元素。
# 假设我们要删除排名高于50的所有国家/地区
for country in root.findall('country'):
# using root.findall() to avoid removal during traversal
rank = int(country.find('rank').text)
if rank > 50:
root.remove(country)
tree.write(r'data/output.xml')
# 请注意在迭代时进行并发修改可能会导致问题,就像在迭代并修改 Python 列表或字典时那样。 因此,这个示例先通过 root.findall() 收集了所有匹配的元素,在此之后再对匹配项列表进行迭代。
# =============================================================================
# 构建XML文档
# =============================================================================
# SubElement() 函数还提供了一种便捷方法来为给定元素创建新的子元素
a = ET.Element('a')
b = ET.SubElement(a, 'b')
c = ET.SubElement(a, 'c')
d = ET.SubElement(c, 'd')
ET.dump(a)