当前位置:首页>python>Python进阶教程:5_XML 解析 —— 新手完全指南

Python进阶教程:5_XML 解析 —— 新手完全指南

  • 2026-08-20 22:29:58
Python进阶教程:5_XML 解析 —— 新手完全指南

一、什么是 XML?

XML(eXtensible Markup Language,可扩展标记语言)是一种用来存储和传输数据的文本格式。

1.1 生活比喻

把 XML 想象成一个带标签的收纳盒

  • 每个盒子有名字(标签名)
  • 盒子里可以放东西(文本内容)
  • 盒子里还可以套小盒子(子元素)
  • 每个盒子可以贴便签(属性)

1.2 XML 长什么样?

<?xml version="1.0" encoding="UTF-8"?><bookstore>    <bookcategory="编程">        <title>Python入门</title>        <author>张三</author>        <price>59.9</price>        <year>2025</year>    </book>    <bookcategory="文学">        <title>红楼梦</title>        <author>曹雪芹</author>        <price>39.0</price>        <year>1791</year>    </book></bookstore>

1.3 XML 的基本结构

<?xml version="1.0" encoding="UTF-8"?>   ← XML 声明(可选)<bookstore>                               ← 根元素(必须有且只有一个)    <bookcategory="编程">                ← 子元素,category 是"属性"        <title>Python入门</title>         ← 子元素,"Python入门"是"文本内容"        <author>张三</author>        <price>59.9</price>    </book></bookstore>

1.4 XML 的术语对照表

<person name="张三" age="25">    ← "person" 是元素(标签)    <city>北京</city>            ← "name""age" 是属性</person>                        ← "北京" 是文本内容
术语
英文
示例
说明
元素
Element
<book>...</book>
一对标签包裹的内容
标签
Tag
book
title
尖括号里的名字
属性
Attribute
category="编程"
写在开始标签里的键值对
文本
Text
Python入门
标签之间的文字
根元素
Root
<bookstore>
最外层的元素
子元素
Child
<book>
 是 <bookstore> 的子元素
嵌套关系
父元素
Parent
<bookstore>
 是 <book> 的父元素
上一级
兄弟元素
Sibling
两个 <book> 互为兄弟
同级

1.5 XML 的规则

✅ 必须有且只有一个根元素✅ 标签必须成对关闭:<title>...</title>✅ 标签必须正确嵌套:<a><b></b></a>  ✅                    <a><b></a></b>  ❌✅ 属性值必须加引号:name="张三"  ✅                    name=张三    ❌✅ 标签名区分大小写:<Title> 和 <title> 是不同的

二、Python 解析 XML 的方式概览

Python 提供了多种解析 XML 的方式:

方式
模块
特点
适合场景
ElementTreexml.etree.ElementTree
简单、轻量、Pythonic
✅ 新手首选,日常使用
minidomxml.dom.minidom
DOM方式,功能全
需要完整DOM操作
SAXxml.sax
事件驱动,流式解析
超大文件,内存敏感
lxmllxml
(第三方)
功能最强,速度快
复杂XPath、性能要求高

本教程重点讲 ElementTree(最常用),其他方式也会介绍。


三、ElementTree —— 最推荐的方式

3.1 导入模块

import xml.etree.ElementTree as ET

约定俗成:用 ET 作为别名。

3.2 准备一个 XML 文件

创建文件 books.xml

<?xml version="1.0" encoding="UTF-8"?><bookstore>    <bookid="1"category="编程">        <title>Python编程:从入门到实践</title>        <author>Eric Matthes</author>        <pricecurrency="CNY">89.00</price>        <year>2020</year>        <tags>            <tag>Python</tag>            <tag>入门</tag>        </tags>    </book>    <bookid="2"category="文学">        <title>百年孤独</title>        <author>加西亚·马尔克斯</author>        <pricecurrency="CNY">55.00</price>        <year>1967</year>        <tags>            <tag>小说</tag>            <tag>魔幻现实主义</tag>        </tags>    </book>    <bookid="3"category="编程">        <title>算法导论</title>        <author>Thomas H. Cormen</author>        <pricecurrency="USD">128.00</price>        <year>2009</year>        <tags>            <tag>算法</tag>            <tag>计算机</tag>        </tags>    </book></bookstore>

3.3 解析 XML 文件(从文件读取)

import xml.etree.ElementTree as ET# ============ 第一步:解析文件,得到"树"对象 ============tree = ET.parse("books.xml")# ============ 第二步:获取根元素 ============root = tree.getroot()# 查看根元素的信息print(f"根元素标签:{root.tag}")        # bookstoreprint(f"根元素属性:{root.attrib}")     # {}(根元素没有属性)print(f"子元素数量:{len(root)}")       # 3(有3个book)

输出

根元素标签:bookstore根元素属性:{}子元素数量:3

3.4 也可以从字符串解析

import xml.etree.ElementTree as ETxml_string = """<student>    <name>小明</name>    <age>20</age>    <grade>大三</grade></student>"""# fromstring() 直接从字符串解析root = ET.fromstring(xml_string)print(root.tag)                    # studentprint(root.find("name").text)      # 小明print(root.find("age").text)       # 20

3.5 遍历所有子元素

import xml.etree.ElementTree as ETtree = ET.parse("books.xml")root = tree.getroot()# ============ 方法1:直接遍历(只遍历直接子元素) ============print("=== 方法1:遍历直接子元素 ===")for book in root:    print(f"  标签:{book.tag},属性:{book.attrib}")# 输出:#   标签:book,属性:{'id': '1', 'category': '编程'}#   标签:book,属性:{'id': '2', 'category': '文学'}#   标签:book,属性:{'id': '3', 'category': '编程'}# ============ 方法2:iter() 遍历所有后代元素(包括子元素的子元素) ============print("\n=== 方法2:遍历所有后代 ===")for elem in root.iter():    print(f"  {elem.tag}{elem.text.strip() if elem.text and elem.text.strip() else'(无文本)'}")# 输出(会列出所有层级的元素):#   bookstore: (无文本)#   book: (无文本)#   title: Python编程:从入门到实践#   author: Eric Matthes#   ...# ============ 方法3:iter() 只遍历指定标签 ============print("\n=== 方法3:只遍历所有 title ===")for title in root.iter("title"):    print(f"  📖 {title.text}")# 输出:#   📖 Python编程:从入门到实践#   📖 百年孤独#   📖 算法导论

3.6 查找元素:find() 和 findall()

这是最常用的操作!

import xml.etree.ElementTree as ETtree = ET.parse("books.xml")root = tree.getroot()# ============ find():找第一个匹配的元素 ============# 找第一个 <book>first_book = root.find("book")print(f"第一本书的标签:{first_book.tag}")print(f"第一本书的属性:{first_book.attrib}")# 找第一个 book 下的 titletitle = first_book.find("title")print(f"书名:{title.text}")# ============ findall():找所有匹配的元素 ============# 找所有 <book>all_books = root.findall("book")print(f"\n共有 {len(all_books)} 本书")# 找所有 book 下的 titleall_titles = root.findall("book/title")  # 路径写法!print("所有书名:")for t in all_titles:    print(f"  - {t.text}")

输出

第一本书的标签:book第一本书的属性:{'id''1''category''编程'}书名:Python编程:从入门到实践共有 3 本书所有书名:  - Python编程:从入门到实践  - 百年孤独  - 算法导论

3.7 路径查找语法(重要!)

find() 和 findall() 支持简单的路径表达式:

路径
含义
示例
"book"
直接子元素中找 book
root.find("book")
"book/title"
book 下的 title
root.find("book/title")
".//title"
任意深度的 title
root.findall(".//title")
"book[@id='1']"
id属性为1的book
root.find("book[@id='1']")
"book[title='百年孤独']"
title文本为百年孤独的book
root.find("book[title='百年孤独']")
"book[1]"
第2个book(索引从0开始)
root.find("book[1]")
"book[last()]"
最后一个book
root.find("book[last()]")
import xml.etree.ElementTree as ETtree = ET.parse("books.xml")root = tree.getroot()# 示例1:找任意深度的所有 tag 元素print("=== 所有 tag ===")for tag in root.findall(".//tag"):    print(f"  🏷️  {tag.text}")# 示例2:找 id="2" 的 bookprint("\n=== 找 id=2 的书 ===")book2 = root.find("book[@id='2']")print(f"  书名:{book2.find('title').text}")print(f"  作者:{book2.find('author').text}")# 示例3:找 category="编程" 的所有书print("\n=== 所有编程类书籍 ===")for book in root.findall("book[@category='编程']"):    print(f"  📗 {book.find('title').text}")# 示例4:找价格大于某个值的(ElementTree不直接支持数值比较,需要手动过滤)print("\n=== 价格 > 60 的书 ===")for book in root.findall("book"):    price = float(book.find("price").text)    if price > 60:        print(f"  💰 {book.find('title').text} - ¥{price}")

输出

=== 所有 tag ===  🏷️  Python  🏷️  入门  🏷️  小说  🏷️  魔幻现实主义  🏷️  算法  🏷️  计算机=== 找 id=2 的书 ===  书名:百年孤独  作者:加西亚·马尔克斯=== 所有编程类书籍 ===  📗 Python编程:从入门到实践  📗 算法导论=== 价格 > 60 的书 ===  💰 Python编程:从入门到实践 - ¥89.0  💰 算法导论 - ¥128.0

3.8 获取元素的详细信息

import xml.etree.ElementTree as ETtree = ET.parse("books.xml")root = tree.getroot()book = root.find("book")  # 第一个 book# ============ 获取标签名 ============print(f"标签名:{book.tag}")              # book# ============ 获取属性 ============print(f"所有属性:{book.attrib}")          # {'id': '1', 'category': '编程'}print(f"id属性:{book.get('id')}")         # 1print(f"category属性:{book.get('category')}")  # 编程print(f"不存在的属性:{book.get('xxx''默认值')}")  # 默认值# ============ 获取文本内容 ============title = book.find("title")print(f"title的文本:{title.text}")        # Python编程:从入门到实践# ============ 获取子元素列表 ============children = list(book)print(f"book的子元素数量:{len(children)}")  # 5 (title, author, price, year, tags)for child in children:    print(f"  子元素:{child.tag} = {child.text}")# ============ 获取父元素(ElementTree 不直接支持,需要自己建映射) ============# 方法:遍历建立 parent 映射parent_map = {child: parent for parent in root.iter() for child in parent}title_elem = root.find(".//title")parent = parent_map[title_elem]print(f"\ntitle 的父元素是:{parent.tag}")  # book

3.9 处理属性(Attribute)

import xml.etree.ElementTree as ETtree = ET.parse("books.xml")root = tree.getroot()# ============ 读取属性 ============for book in root.findall("book"):    book_id = book.get("id")           # 获取单个属性    category = book.get("category")    print(f"  ID={book_id}, 类别={category}")# ============ 读取子元素的属性 ============for book in root.findall("book"):    price_elem = book.find("price")    currency = price_elem.get("currency")  # price 标签上的 currency 属性    value = price_elem.text    print(f"  价格:{value}{currency}")# 输出:#   价格:89.00 CNY#   价格:55.00 CNY#   价格:128.00 USD

3.10 处理命名空间(Namespace)

有些 XML 带有命名空间,解析时会比较麻烦:

<?xml version="1.0"?><rootxmlns:ns="http://example.com/schema">    <ns:item>        <ns:name>测试</ns:name>    </ns:item></root>
import xml.etree.ElementTree as ETxml_string = """<?xml version="1.0"?><root xmlns:ns="http://example.com/schema">    <ns:item>        <ns:name>测试数据</ns:name>    </ns:item></root>"""root = ET.fromstring(xml_string)# ❌ 这样找不到(因为标签名实际是 "{http://example.com/schema}item")# item = root.find("ns:item")  # 返回 None# ✅ 方法1:使用完整命名空间ns = {"ns""http://example.com/schema"}item = root.find("ns:item", ns)name = item.find("ns:name", ns)print(f"方法1:{name.text}")  # 测试数据# ✅ 方法2:用通配符(忽略命名空间)item = root.find("{*}item")name = item.find("{*}name")print(f"方法2:{name.text}")  # 测试数据# 查看实际的标签名print(f"实际标签名:{item.tag}")# 输出:{http://example.com/schema}item

四、创建和修改 XML

4.1 从零创建 XML

import xml.etree.ElementTree as ET# ============ 创建根元素 ============root = ET.Element("students")# ============ 添加子元素 ============# 创建第一个学生student1 = ET.SubElement(root, "student", attrib={"id""1""class""三班"})name1 = ET.SubElement(student1, "name")name1.text = "张三"age1 = ET.SubElement(student1, "age")age1.text = "20"score1 = ET.SubElement(student1, "score")score1.text = "95"# 创建第二个学生student2 = ET.SubElement(root, "student", attrib={"id""2""class""一班"})name2 = ET.SubElement(student2, "name")name2.text = "李四"age2 = ET.SubElement(student2, "age")age2.text = "21"score2 = ET.SubElement(student2, "score")score2.text = "88"# ============ 写入文件 ============tree = ET.ElementTree(root)# 方法1:简单写入tree.write("students.xml", encoding="utf-8", xml_declaration=True)# 方法2:格式化写入(Python 3.9+)ET.indent(tree, space="    ")  # 添加缩进tree.write("students_formatted.xml", encoding="utf-8", xml_declaration=True)print("✅ XML 文件创建成功!")

生成的 students_formatted.xml

<?xml version='1.0' encoding='utf-8'?><students>    <studentid="1"class="三班">        <name>张三</name>        <age>20</age>        <score>95</score>    </student>    <studentid="2"class="一班">        <name>李四</name>        <age>21</age>        <score>88</score>    </student></students>

4.2 修改现有 XML

import xml.etree.ElementTree as ETtree = ET.parse("books.xml")root = tree.getroot()# ============ 修改文本 ============# 把第一本书的价格改为 99.00first_book = root.find("book")price = first_book.find("price")print(f"修改前价格:{price.text}")   # 89.00price.text = "99.00"print(f"修改后价格:{price.text}")   # 99.00# ============ 修改属性 ============first_book.set("category""热门编程")  # 修改已有属性first_book.set("recommended""true")   # 添加新属性print(f"修改后属性:{first_book.attrib}")# ============ 添加新元素 ============# 给第一本书添加 <publisher> 元素publisher = ET.SubElement(first_book, "publisher")publisher.text = "人民邮电出版社"# ============ 删除元素 ============# 删除第一本书的 <year> 元素year = first_book.find("year")first_book.remove(year)# ============ 保存修改 ============ET.indent(tree, space="    ")tree.write("books_modified.xml", encoding="utf-8", xml_declaration=True)print("✅ 修改已保存!")

4.3 在指定位置插入元素

import xml.etree.ElementTree as ETroot = ET.Element("fruits")# 添加几个水果ET.SubElement(root, "fruit").text = "苹果"ET.SubElement(root, "fruit").text = "香蕉"ET.SubElement(root, "fruit").text = "橘子"# 在索引1的位置插入(插在"苹果"和"香蕉"之间)new_fruit = ET.Element("fruit")new_fruit.text = "葡萄"root.insert(1, new_fruit)# 查看结果for fruit in root:    print(fruit.text)# 输出:# 苹果# 葡萄    ← 插入在这里# 香蕉# 橘子

五、xml.dom.minidom —— DOM 方式解析

5.1 什么是 DOM?

DOM(Document Object Model)把整个 XML 加载到内存中,形成一个树形结构,你可以随意遍历、修改任何节点。

和 ElementTree 的区别

  • ElementTree:更 Pythonic,API 更简洁
  • minidom:更接近 W3C 标准,方法名更长,但功能更全

5.2 基本用法

from xml.dom import minidom# 解析文件dom = minidom.parse("books.xml")# 获取根元素root = dom.documentElementprint(f"根元素:{root.tagName}")  # bookstore# 获取所有 book 元素books = root.getElementsByTagName("book")print(f"共有 {len(books)} 本书\n")# 遍历每本书for book in books:    # 获取属性    book_id = book.getAttribute("id")    category = book.getAttribute("category")    # 获取子元素的文本    title = book.getElementsByTagName("title")[0].firstChild.data    author = book.getElementsByTagName("author")[0].firstChild.data    price = book.getElementsByTagName("price")[0].firstChild.data    print(f"  [{book_id}] 《{title}》 - {author} - ¥{price} ({category})")

输出

根元素:bookstore共有 3 本书  [1] 《Python编程:从入门到实践》 - Eric Matthes - ¥89.00 (编程)  [2] 《百年孤独》 - 加西亚·马尔克斯 - ¥55.00 (文学)  [3] 《算法导论》 - Thomas H. Cormen - ¥128.00 (编程)

5.3 minidom 的常用方法对照

操作
ElementTree
minidom
解析文件
ET.parse("file.xml")minidom.parse("file.xml")
获取根
tree.getroot()dom.documentElement
标签名
elem.tagnode.tagName
文本内容
elem.textnode.firstChild.data
获取属性
elem.get("name")node.getAttribute("name")
找子元素
elem.find("title")node.getElementsByTagName("title")
所有子元素
list(elem)node.childNodes

5.4 用 minidom 创建 XML

from xml.dom import minidom# 创建文档doc = minidom.Document()# 创建根元素root = doc.createElement("config")doc.appendChild(root)# 创建子元素server = doc.createElement("server")server.setAttribute("host""192.168.1.1")server.setAttribute("port""8080")root.appendChild(server)# 创建带文本的子元素name = doc.createElement("name")name_text = doc.createTextNode("我的服务器")name.appendChild(name_text)server.appendChild(name)# 格式化输出xml_string = doc.toprettyxml(indent="    ", encoding="utf-8")print(xml_string.decode("utf-8"))# 保存到文件with open("config.xml""w", encoding="utf-8") as f:    doc.writexml(f, indent="    ", addindent="    ", newl="\n", encoding="utf-8")

输出

<?xml version="1.0" encoding="utf-8"?><config>    <serverhost="192.168.1.1"port="8080">        <name>我的服务器</name>    </server></config>

六、xml.sax —— 流式解析(处理大文件)

6.1 什么是 SAX?

SAX(Simple API for XML)是事件驱动的解析方式:

  • 不会把整个文件加载到内存
  • 从上往下逐行读取
  • 遇到开始标签、结束标签、文本时触发回调函数

生活比喻

  • DOM/ElementTree
     = 把整本书搬到桌子上,随便翻
  • SAX
     = 像听有声书,从头听到尾,听到关键内容就记下来

适合场景:几百MB甚至几GB的XML文件。

6.2 基本用法

import xml.sax# ============ 定义事件处理器 ============class BookHandler(xml.sax.ContentHandler):    def __init__(self):        super().__init__()        self.books = []          # 存储所有书        self.current_book = {}   # 当前正在解析的书        self.current_tag = ""    # 当前标签名        self.in_book = False     # 是否在 book 元素内    # 遇到开始标签时触发    # name: 标签名, attrs: 属性字典    def startElement(self, name, attrs):        self.current_tag = name        if name == "book":            self.in_book = True            self.current_book = {                "id": attrs.get("id"""),                "category": attrs.get("category"""),            }    # 遇到文本内容时触发    def characters(self, content):        content = content.strip()        if not content:            return        if self.in_book and self.current_tag in ("title""author""price""year"):            self.current_book[self.current_tag] = content    # 遇到结束标签时触发    def endElement(self, name):        if name == "book":            self.in_book = False            self.books.append(self.current_book)            self.current_book = {}        self.current_tag = ""# ============ 使用 ============handler = BookHandler()# 解析文件parser = xml.sax.make_parser()parser.setContentHandler(handler)parser.parse("books.xml")# 输出结果print(f"共解析了 {len(handler.books)} 本书:\n")for book in handler.books:    print(f"  [{book['id']}] 《{book.get('title''?')}》")    print(f"       作者:{book.get('author''?')}")    print(f"       价格:¥{book.get('price''?')}")    print(f"       类别:{book.get('category''?')}")    print()

输出

共解析了 3 本书:  [1] 《Python编程:从入门到实践》       作者:Eric Matthes       价格:¥89.00       类别:编程  [2] 《百年孤独》       作者:加西亚·马尔克斯       价格:¥55.00       类别:文学  [3] 《算法导论》       作者:Thomas H. Cormen       价格:¥128.00       类别:编程

6.3 SAX 的回调方法总结

方法
触发时机
参数
startDocument()
文档开始
endDocument()
文档结束
startElement(name, attrs)
遇到 <tag>
标签名、属性
endElement(name)
遇到 </tag>
标签名
characters(content)
遇到文本内容
文本字符串

七、lxml —— 第三方强大库(可选)

7.1 安装

pip install lxml

7.2 为什么用 lxml?

  • 支持完整的 XPath(比 ElementTree 的路径语法强大得多)
  • 速度更快(底层用 C 实现)
  • 支持 XSLT 转换
  • API 和 ElementTree 兼容

7.3 基本用法

from lxml import etree# 解析文件tree = etree.parse("books.xml")root = tree.getroot()# ============ 强大的 XPath ============# 找所有价格大于60的书(ElementTree做不到!)expensive_books = root.xpath("//book[price > 60]/title/text()")print("价格>60的书:", expensive_books)# ['Python编程:从入门到实践', '算法导论']# 找所有编程类书的作者authors = root.xpath("//book[@category='编程']/author/text()")print("编程书作者:", authors)# ['Eric Matthes', 'Thomas H. Cormen']# 获取所有 tag 的文本tags = root.xpath("//tag/text()")print("所有标签:", tags)# ['Python', '入门', '小说', '魔幻现实主义', '算法', '计算机']# 获取第一本书的所有属性attrs = root.xpath("//book[1]/@*")print("第一本书属性:", attrs)# ['1', '编程']# 统计每个类别有几本书categories = root.xpath("//book/@category")from collections import Counterprint("类别统计:"dict(Counter(categories)))# {'编程': 2, '文学': 1}

7.4 XPath 常用语法速查

XPath 表达式
含义
/bookstore/book
根下的直接子 book
//book
任意位置的 book
//book/title
所有 book 下的 title
//book[@id='1']
id=1 的 book
//book[price>60]
price 大于 60 的 book
//book[1]
第一个 book
//book[last()]
最后一个 book
//book/@category
所有 book 的 category 属性值
//title/text()
所有 title 的文本内容
//book[contains(title,'Python')]
title 包含 Python 的 book
count(//book)
book 的数量

八、实战案例

8.1 解析 RSS/Atom 订阅源

import xml.etree.ElementTree as ETimport urllib.requestdef parse_rss(url):    """解析 RSS 订阅源"""    # 下载 XML    response = urllib.request.urlopen(url)    xml_data = response.read()    # 解析    root = ET.fromstring(xml_data)    # RSS 结构:rss > channel > item    channel = root.find("channel")    title = channel.find("title").text    print(f"📰 频道:{title}\n")    items = channel.findall("item")    for i, item in enumerate(items[:5], 1):  # 只显示前5条        item_title = item.find("title").text        item_link = item.find("link").text        pub_date = item.find("pubDate")        date_str = pub_date.text if pub_date is not None else "未知"        print(f"  {i}{item_title}")        print(f"     🔗 {item_link}")        print(f"     📅 {date_str}")        print()# 使用(示例URL,可能失效)# parse_rss("https://example.com/rss.xml")

8.2 解析 Android 布局文件

import xml.etree.ElementTree as ETandroid_layout = """<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical">    <TextView        android:id="@+id/title_text"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="Hello World"        android:textSize="24sp" />    <Button        android:id="@+id/submit_btn"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="提交" />    <EditText        android:id="@+id/input_field"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:hint="请输入内容" /></LinearLayout>"""# Android XML 有命名空间ns = {"android""http://schemas.android.com/apk/res/android"}root = ET.fromstring(android_layout)print(f"根布局:{root.tag}")print(f"方向:{root.get('{http://schemas.android.com/apk/res/android}orientation')}")print()# 遍历所有控件for elem in root:    tag = elem.tag.split("}")[-1] if "}" in elem.tag else elem.tag  # 去掉命名空间前缀    android_id = elem.get("{http://schemas.android.com/apk/res/android}id""")    text = elem.get("{http://schemas.android.com/apk/res/android}text""")    print(f"  📱 {tag}")    if android_id:        print(f"     ID: {android_id}")    if text:        print(f"     文本: {text}")

输出

根布局:{http://schemas.android.com/apk/res/android}LinearLayout方向:vertical  📱 TextView     ID: @+id/title_text     文本: Hello World  📱 Button     ID: @+id/submit_btn     文本: 提交  📱 EditText     ID: @+id/input_field

8.3 XML 转 JSON

import xml.etree.ElementTree as ETimport jsondef xml_to_dict(element):    """递归将 XML 元素转为字典"""    result = {}    # 添加属性    if element.attrib:        result["@attributes"] = element.attrib    # 处理子元素    children = list(element)    if children:        child_dict = {}        for child in children:            child_data = xml_to_dict(child)            # 如果有多个同名子元素,转为列表            if child.tag in child_dict:                if not isinstance(child_dict[child.tag], list):                    child_dict[child.tag] = [child_dict[child.tag]]                child_dict[child.tag].append(child_data)            else:                child_dict[child.tag] = child_data        result.update(child_dict)    # 添加文本    if element.text and element.text.strip():        if result:            result["#text"] = element.text.strip()        else:            return element.text.strip()    return result# 使用tree = ET.parse("books.xml")root = tree.getroot()data = {root.tag: xml_to_dict(root)}json_string = json.dumps(data, ensure_ascii=False, indent=2)print(json_string)# 保存到文件with open("books.json""w", encoding="utf-8"as f:    f.write(json_string)print("\n✅ 已保存为 books.json")

8.4 批量生成 XML(如:导出报表)

import xml.etree.ElementTree as ETfrom datetime import datetimedef generate_report_xml(students_data, output_file):    """生成学生成绩报表 XML"""    # 创建根元素    root = ET.Element("report")    root.set("generated", datetime.now().strftime("%Y-%m-%d %H:%M:%S"))    root.set("total_students"str(len(students_data)))    # 添加元信息    meta = ET.SubElement(root, "metadata")    ET.SubElement(meta, "school").text = "XX大学"    ET.SubElement(meta, "semester").text = "2025-2026学年第二学期"    # 添加学生数据    students_elem = ET.SubElement(root, "students")    for student in students_data:        s = ET.SubElement(students_elem, "student")        s.set("id"str(student["id"]))        ET.SubElement(s, "name").text = student["name"]        ET.SubElement(s, "major").text = student["major"]        # 成绩列表        scores = ET.SubElement(s, "scores")        for course, score in student["scores"].items():            score_elem = ET.SubElement(scores, "course")            score_elem.set("name", course)            score_elem.text = str(score)        # 计算平均分        avg = sum(student["scores"].values()) / len(student["scores"])        ET.SubElement(s, "average").text = f"{avg:.1f}"    # 格式化并保存    tree = ET.ElementTree(root)    ET.indent(tree, space="    ")    tree.write(output_file, encoding="utf-8", xml_declaration=True)    print(f"✅ 报表已生成:{output_file}")# 测试数据students = [    {        "id"1001,        "name""张三",        "major""计算机科学",        "scores": {"数学"92"英语"85"Python"98}    },    {        "id"1002,        "name""李四",        "major""软件工程",        "scores": {"数学"78"英语"91"Python"88}    },]generate_report_xml(students, "report.xml")

生成的 report.xml

<?xml version='1.0' encoding='utf-8'?><reportgenerated="2026-07-29 11:00:00"total_students="2">    <metadata>        <school>XX大学</school>        <semester>2025-2026学年第二学期</semester>    </metadata>    <students>        <studentid="1001">            <name>张三</name>            <major>计算机科学</major>            <scores>                <coursename="数学">92</course>                <coursename="英语">85</course>                <coursename="Python">98</course>            </scores>            <average>91.7</average>        </student>        <studentid="1002">            <name>李四</name>            <major>软件工程</major>            <scores>                <coursename="数学">78</course>                <coursename="英语">91</course>                <coursename="Python">88</course>            </scores>            <average>85.7</average>        </student>    </students></report>

九、错误处理

import xml.etree.ElementTree as ET# ============ 处理文件不存在 ============try:    tree = ET.parse("not_exist.xml")except FileNotFoundError:    print("❌ 文件不存在!")# ============ 处理 XML 格式错误 ============bad_xml = "<root><unclosed></root>"  # 标签未正确关闭try:    root = ET.fromstring(bad_xml)except ET.ParseError as e:    print(f"❌ XML 解析错误:{e}")    # 输出:XML 解析错误:mismatched tag: line 1, column 15# ============ 处理元素不存在 ============xml_str = "<root><name>test</name></root>"root = ET.fromstring(xml_str)# find() 找不到时返回 Noneage = root.find("age")if age is None:    print("⚠️ 没有找到 age 元素")else:    print(age.text)# 安全获取文本的辅助函数def safe_text(element, path, default=""):    """安全获取元素文本"""    found = element.find(path)    if found is not None and found.text:        return found.text.strip()    return default# 使用name = safe_text(root, "name""未知")age = safe_text(root, "age""0")print(f"姓名:{name},年龄:{age}")

十、性能对比与选择建议

import timeimport xml.etree.ElementTree as ETfrom xml.dom import minidomfrom lxml import etree# 生成一个大 XML 用于测试def generate_large_xml(filename, count=100000):    root = ET.Element("data")    for i in range(count):        item = ET.SubElement(root, "item"id=str(i))        ET.SubElement(item, "name").text = f"Item_{i}"        ET.SubElement(item, "value").text = str(i * 1.5)    tree = ET.ElementTree(root)    tree.write(filename)    print(f"生成了 {count} 条记录的测试文件")generate_large_xml("large_test.xml"100000)# 测试 ElementTreestart = time.time()tree = ET.parse("large_test.xml")root = tree.getroot()count = len(root.findall("item"))print(f"ElementTree:{time.time()-start:.3f}秒,{count}条")# 测试 minidomstart = time.time()dom = minidom.parse("large_test.xml")items = dom.getElementsByTagName("item")print(f"minidom:    {time.time()-start:.3f}秒,{len(items)}条")# 测试 lxmlstart = time.time()tree = etree.parse("large_test.xml")root = tree.getroot()count = len(root.findall("item"))print(f"lxml:       {time.time()-start:.3f}秒,{count}条")

典型结果(仅供参考):

ElementTree0.45秒,100000minidom:    2.10秒,100000lxml:       0.18秒,100000

选择建议

┌────────────────────────────────────────────────────────┐│  文件 < 10MB,日常使用                                  ││  → xml.etree.ElementTree ✅(够用、简单)               │├────────────────────────────────────────────────────────┤│  需要复杂 XPath、XSLT、高性能                            ││  → lxml ✅                                             │├────────────────────────────────────────────────────────┤│  文件 > 100MB,内存有限                                 ││  → xml.sax(流式解析)✅                                │├────────────────────────────────────────────────────────┤│  需要 W3C 标准 DOM 操作                                 ││  → xml.dom.minidom                                     │└────────────────────────────────────────────────────────┘

十一、常见问题 FAQ

Q1:解析时中文乱码?

# 确保文件编码和声明一致# XML 声明写 encoding="UTF-8",文件也要保存为 UTF-8# 读取时指定编码withopen("file.xml""r", encoding="utf-8"as f:    content = f.read()root = ET.fromstring(content)

Q2:text 返回 None?

# 如果元素没有文本内容(只有子元素),text 是 None# <book><title>xxx</title></book># book.text → None(因为 book 和 title 之间只有空白)# book.find("title").text → "xxx"# 安全写法:text = elem.text or ""  # 如果是 None 就用空字符串text = (elem.text or "").strip()  # 还要去掉首尾空白

Q3:如何忽略命名空间?

# 方法:解析前去掉命名空间import redef remove_namespace(xml_string):    """去掉 XML 中的所有命名空间"""    return re.sub(r'xmlns[^=]*="[^"]*"''', xml_string)clean_xml = remove_namespace(raw_xml)root = ET.fromstring(clean_xml)

Q4:ElementTree 和 lxml 的 API 兼容吗?

# 大部分兼容!切换只需改导入:# ElementTreeimport xml.etree.ElementTree as ET# lxml(API 几乎一样)from lxml import etree as ET# 后面的代码基本不用改tree = ET.parse("file.xml")root = tree.getroot()

十二、速查表

解析文件:      tree = ET.parse("file.xml")解析字符串:    root = ET.fromstring(xml_string)获取根元素:    root = tree.getroot()标签名:        elem.tag文本内容:      elem.text属性:          elem.get("name") / elem.attrib找第一个:      elem.find("path")找所有:        elem.findall("path")任意深度找:    elem.findall(".//tag")按属性找:      elem.find("tag[@attr='value']")遍历所有后代:  for e in root.iter():遍历指定标签:  for e in root.iter("title"):创建元素:      ET.Element("tag")创建子元素:    ET.SubElement(parent, "tag")设置文本:      elem.text = "内容"设置属性:      elem.set("key""value")添加子元素:    parent.append(child)删除子元素:    parent.remove(child)插入元素:      parent.insert(index, child)保存到文件:    tree.write("out.xml", encoding="utf-8", xml_declaration=True)格式化缩进:    ET.indent(tree, space="    ")  # Python 3.9+

十三、学习路径建议

第1步:理解 XML 的结构(标签、属性、文本、嵌套)第2步:用 ET.parse() 解析文件,用 find/findall 查找元素第3步:用 iter() 遍历,用 get() 获取属性第4步:学习路径语法(.//tag、[@attr='val'])第5步:练习创建和修改 XML第6步:了解 minidom 和 SAX 的区别第7步:(进阶)学习 lxml 和 XPath第8步:实战(解析配置文件、RSS、API返回的XML等)

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-08-21 13:36:34 HTTP/2.0 GET : https://f.mffb.com.cn/a/509433.html
  2. 运行时间 : 0.307565s [ 吞吐率:3.25req/s ] 内存消耗:4,999.83kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=0faeec0656eab47556142f399635d148
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000905s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.001343s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.026035s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000763s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.001689s ]
  6. SELECT * FROM `set` [ RunTime:0.029427s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.001655s ]
  8. SELECT * FROM `article` WHERE `id` = 509433 LIMIT 1 [ RunTime:0.037178s ]
  9. UPDATE `article` SET `lasttime` = 1787290595 WHERE `id` = 509433 [ RunTime:0.009119s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 66 LIMIT 1 [ RunTime:0.000906s ]
  11. SELECT * FROM `article` WHERE `id` < 509433 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.000499s ]
  12. SELECT * FROM `article` WHERE `id` > 509433 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.000452s ]
  13. SELECT * FROM `article` WHERE `id` < 509433 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.000802s ]
  14. SELECT * FROM `article` WHERE `id` < 509433 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.000704s ]
  15. SELECT * FROM `article` WHERE `id` < 509433 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.000736s ]
0.308985s