python3使用lxml解析xml时踩坑记录

文章目录

以下是使用 Python 的 lxml 库解析并提取 XML 数据的完整示例代码:

python

复制

from lxml import etree

你的 XML 数据

xml_data = '''<?xml version="1.0" encoding="utf-8"?>

'''

解析 XML

root = etree.fromstring(xml_data.encode('utf-8'))

----------------------------

1. 获取 mlt 根元素的属性

----------------------------

mlt_attributes = {

'version': root.get('version'),

'title': root.get('title'),

'LC_NUMERIC': root.get('LC_NUMERIC')

}

print("MLT 根元素属性:")

for k, v in mlt_attributes.items():

print(f"{k}: {v}")

----------------------------

2. 获取 chain 元素的属性

----------------------------

chain = root.find('chain')

chain_info = {

'id': chain.get('id'),

'title': chain.get('title'),

'duration': chain.get('out')

}

print("\nChain 元素属性:")

for k, v in chain_info.items():

print(f"{k}: {v}")

----------------------------

3. 获取所有 property 的值

----------------------------

print("\n关键 Property 列表:")

properties = [

'length', 'resource',

'meta.media.width', 'meta.media.height',

'meta.media.0.codec.name', 'creation_time'

]

for prop_name in properties:

使用 XPath 精确查找

prop = chain.xpath(f'property[@name="{prop_name}"]')

if prop:

print(f"{prop_name}: {prop[0].text}")

else:

print(f"{prop_name}: Not Found")

----------------------------

4. 获取所有视频流信息(扩展示例)

----------------------------

print("\n视频流详细信息:")

for i in range(2): # 根据示例数据有 2 个流

stream_type = chain.xpath(f'property[@name="meta.media.{i}.stream.type"]')

if stream_type:

stream_type = stream_type[0].text

codec_name = chain.xpath(f'property[@name="meta.media.{i}.codec.name"]')[0].text

print(f"Stream {i}:")

print(f" Type: {stream_type}")

print(f" Codec: {codec_name}")

复制代码
    if stream_type == 'video':
        resolution = f"{chain.xpath(f'property[@name="meta.media.{i}.codec.width"]')[0].text}x" \
                     f"{chain.xpath(f'property[@name="meta.media.{i}.codec.height"]')[0].text}"
        print(f"  Resolution: {resolution}")

代码说明:

XML 解析:使用 etree.fromstring() 解析 XML 字符串

根元素属性:直接通过元素的 get() 方法获取属性值

子元素定位:

find() 用于获取第一个匹配的子元素

xpath() 用于复杂查询(支持完整的 XPath 1.0 语法)

属性提取:

使用 element.get('attribute_name') 获取元素属性

使用 element.text 获取元素文本内容

输出示例:

text

复制

MLT 根元素属性:

version: 7.24.0

title: Shotcut version 25.03.14

LC_NUMERIC: C

Chain 元素属性:

id: chain0

title: Shotcut version 25.03.14

duration: 00:00:31.467

关键 Property 列表:

length: 00:00:31.500

resource: E:/test/video/test_game_video/7.mp4

meta.media.width: 1920

meta.media.height: 1080

meta.media.0.codec.name: h264

creation_time: 2025-02-05T07:19:51

视频流详细信息:

Stream 0:

Type: video

Codec: h264

Resolution: 1920x1080

Stream 1:

Type: audio

Codec: aac

注意事项:

对于需要处理命名空间的 XML,需要注册命名空间

XPath 表达式中的属性值匹配要完全一致(包括大小写)

使用 .encode('utf-8') 确保正确处理中文字符

使用防御性编程检查元素是否存在(示例中简化为直接访问,实际生产环境建议添加校验)

如果需要处理更复杂的 XML 结构或需要其他特定数据提取方式,可以进一步扩展这些基础方法。

根据上面的代码,报错'lxml.etree._Element' object has no attribute 'getroot' 'lxml.etree._ElementTree' object has no attribute 'get'

你遇到的错误是由于混淆了两种不同的 XML 解析对象类型:Element 和 ElementTree。以下是完整解决方案:

python

复制

from lxml import etree

xml_data = '''<?xml version="1.0" encoding="utf-8"?>

'''

===================================

正确解析方式选择(二选一):

===================================

方案一:直接解析为 Element (适用于字符串数据)

root = etree.fromstring(xml_data.encode('utf-8')) # 直接得到根元素

方案二:使用 ElementTree (适用于文件解析)

如果是文件路径:

tree = etree.parse("your_file.xml")

root = tree.getroot() # 这才是正确获取根元素的方式

===================================

错误点分析:

===================================

错误用法示例:

tree = etree.fromstring(xml_data) # 返回的是 Element

root = tree.getroot() # ❌ Element 没有 getroot() 方法

===================================

正确使用示范:

===================================

1. 获取根元素属性

print("根元素属性:")

print(f"版本: {root.get('version')}") # ✅ 正确访问方式

print(f"标题: {root.get('title')}")

2. 访问子元素

chain = root.find('chain') # 返回 Element 对象

if chain is not None: # 安全判断

print("\nChain 元素属性:")

print(f"ID: {chain.get('id')}")

print(f"时长: {chain.get('out')}")

3. 获取 property 值的推荐方式

def get_property(element, name):

"""安全获取 property 值的辅助函数"""

prop = element.xpath(f'property[@name="{name}"]')

return prop[0].text if prop else None

if chain is not None:

print("\n关键属性值:")

print(f"视频长度: {get_property(chain, 'length')}")

print(f"文件路径: {get_property(chain, 'resource')}")

print(f"分辨率: {get_property(chain, 'meta.media.width')}x{get_property(chain, 'meta.media.height')}")

关键区别说明:

方法 返回类型 适用场景 获取根元素方式

etree.fromstring() Element 解析字符串/字节数据 直接返回根元素

etree.parse() ElementTree 解析文件/文件类对象 需要 .getroot()

常见错误场景分析:

错误调用 getroot():

python

复制

错误:fromstring 返回的是 Element,没有 getroot()

root = etree.fromstring(xml_data).getroot() # ❌ 会报错

正确:直接使用

root = etree.fromstring(xml_data) # ✅

混淆对象类型:

python

复制

错误:在 ElementTree 对象上直接访问属性

tree = etree.parse("file.xml")

print(tree.get('version')) # ❌ ElementTree 没有 get() 方法

正确:先获取根元素

root = tree.getroot() # ✅

print(root.get('version'))

未做空值判断:

python

复制

危险:直接访问可能不存在的元素

print(root.find('non_exist_tag').get('attr')) # ❌ 可能抛出 AttributeError

安全:添加空值判断

element = root.find('non_exist_tag')

if element is not None:

print(element.get('attr'))

最佳实践建议:

统一使用方案:

python

复制

字符串数据解析

def parse_xml_string(xml_str):

root = etree.fromstring(xml_str)

后续处理 root...

文件解析

def parse_xml_file(file_path):

tree = etree.parse(file_path)

root = tree.getroot()

后续处理 root...

使用类型检查:

python

复制

print(type(root)) # 输出:<class 'lxml.etree._Element'>

print(type(etree.parse("file.xml"))) # 输出:<class 'lxml.etree._ElementTree'>

增强错误处理:

python

复制

try:

root = etree.fromstring(xml_data)

chain = root.find('chain')

if chain is None:

raise ValueError("Chain element not found")

复制代码
resource = get_property(chain, 'resource')
print(f"资源路径: {resource}")

except etree.XMLSyntaxError as e:

print(f"XML 解析错误: {e}")

except Exception as e:

print(f"其他错误: {e}")

通过以上修正和规范,你可以避免这类对象类型错误,并建立更健壮的 XML 解析代码结构。

依据上面回答,采用root = etree.fromstring(xml_data) 的方式,如何遍历根下面的所有子节点

以下是使用 lxml 的 Element 对象遍历根节点下所有子节点的完整方法,通过逐步分析实现:

  1. 基础遍历方法
    python
    复制
    from lxml import etree

xml_data = '''<?xml version="1.0" encoding="utf-8"?>

00:00:31.500

E:/test/video/test_game_video/7.mp4

'''

解析 XML 获取根元素

root = etree.fromstring(xml_data.encode('utf-8'))

----------------------------

方法一:直接遍历子元素

----------------------------

print("所有直接子节点:")

for child in root.iterchildren():

print(f"标签名: {child.tag}")

print(f"属性: {child.attrib}")

print(f"文本内容: {child.text.strip() if child.text else '无'}")

print("-" * 30)

  1. 扩展遍历方式

2.1 使用 XPath 定位

python

复制

----------------------------

方法二:通过 XPath 获取所有子节点

----------------------------

all_children = root.xpath('./*') # 获取直接子元素

print(f"共找到 {len(all_children)} 个直接子节点")

for idx, element in enumerate(all_children, 1):

print(f"\n节点 {idx}:")

print(f"标签类型: {element.tag}")

print(f"属性列表: {element.keys()}")

if element.attrib.get('name'):

print(f"特殊属性 name 的值: {element.get('name')}")

2.2 深度遍历(递归所有后代)

python

复制

----------------------------

方法三:递归遍历所有后代节点

----------------------------

def traverse(element, depth=0):

prefix = " " * depth

print(f"{prefix}层级 {depth}: [{element.tag}]")

for child in element.iterchildren():

traverse(child, depth + 1)

print("\n递归遍历结构:")

traverse(root)

  1. 针对特定场景的遍历

3.1 过滤特定标签

python

复制

只获取 property 节点

properties = root.xpath('//property')

print(f"\n找到 {len(properties)} 个 property 节点:")

for prop in properties:

print(f"属性名: {prop.get('name')} => 值: {prop.text}")

3.2 带条件的遍历

python

复制

获取名字包含 'media' 的属性节点

media_props = root.xpath('//property[contains(@name, "media")]')

print("\n包含 'media' 的属性:")
for p in media_props:
print(f"{p.get('name')}: {p.text}")
4. 输出结果示例
text
复制
所有直接子节点:
标签名: chain
属性: {'id': 'chain0', 'title': 'Shotcut version 25.03.14', 'out': '00:00:31.467'}
文本内容: 无

共找到 1 个直接子节点

节点 1:

标签类型: chain

属性列表: ['id', 'title', 'out']

特殊属性 name 的值: None

递归遍历结构:

层级 0: [mlt]

层级 1: [chain]

层级 2: [property]

层级 2: [property]

找到 2 个 property 节点:

属性名: length => 值: 00:00:31.500

属性名: resource => 值: E:/test/video/test_game_video/7.mp4

包含 'media' 的属性:

meta.media.width: 1920

meta.media.height: 1080

  1. 关键要点总结

方法 特点 适用场景

iterchildren() 直接访问子元素,内存效率高 只需要直接子节点时

XPath ./* 灵活,可配合复杂条件 需要过滤或特殊定位时

递归遍历 获取完整节点结构 需要分析整体文档结构时

XPath 条件过滤 精准定位特定特征节点 提取特定数据时

  1. 高级技巧

6.1 处理命名空间

如果 XML 包含命名空间:

python

复制

ns = {'mlt': 'http://example.org/ns'} # 替换为实际的命名空间

chains = root.xpath('//mlt:chain', namespaces=ns)

6.2 性能优化

对于大型 XML 使用 iterparse() 流式解析:

python

复制

context = etree.iterparse(StringIO(xml_data), events=("start", "end"))

for event, elem in context:

if event == "start" and elem.tag == "property":

print(f"找到属性: {elem.get('name')}")

elem.clear() # 及时清理已处理元素

6.3 数据类型转换

python

复制

将属性值转换为 Python 类型

width = int(root.xpath('//property[@name="meta.media.width"]/text()')[0])

is_progressive = bool(root.xpath('//property[@name="meta.media.progressive"]/text()')[0] == '1')

通过以上方法,你可以根据具体需求选择最适合的遍历方式。实际应用中建议结合 try-except 块处理可能的节点缺失情况。

相关推荐
蜡笔小新..1 小时前
Jupyter Notebook 常用命令(自用)
python·jupyter
褚琅姈1 小时前
Bash语言的测试框架
开发语言·后端·golang
紧跟先前的步伐1 小时前
【Golang】第七弹----map
开发语言·后端·golang
Dxy12393102161 小时前
python如何清除html中所有的字体大小样式
开发语言·python·html
~kiss~2 小时前
go~协程阻塞分析
开发语言·后端·golang
郭逍遥3 小时前
[学习笔记] 部署Docker搭建靶场
笔记·python·学习·ubuntu·docker·容器·flask
时光呢4 小时前
JAVA泛型擦除原理
java·开发语言
ヾChen5 小时前
数据结构——串
数据结构·python·物联网·学习·算法·c#
FreakStudio6 小时前
一文速通Python并行计算:01 Python多线程编程-基本概念、切换流程、GIL锁机制和生产者与消费者模型
python·嵌入式·多线程·面向对象·并行计算·电子diy
Swift社区6 小时前
掌握新编程语言的秘诀:利用 AI 快速上手 Python、Go、Java 和 Rust
人工智能·python·golang