You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Python与SAX高效读取解析大型XML文件?

问题描述

环境与项目背景

  • 系统环境:Windows 11 / Python 3.8.10
  • 使用IDE:Spyder、PyCharm
  • 项目需求:处理大型XML文件,实现7*24小时并发解析、数据存入数据库,后续基于数据库数据生成新XML文件

目标XML结构示例

<PillCall XMLInstanceID="98089D9A-768A-4FA0-A7CD-DC5966EB5B06" PillCallID="49" VersionNumber="1.2">
</PillCall>

当前问题与尝试代码

基础SAX解析代码(Spyder可运行,PyCharm无输出)

尝试过ElementTree、BeautifulSoup均未成功,目前使用SAX编写了基础解析程序:

import xml.sax

class XMLHandler(xml.sax.ContentHandler):
    def __init__(self):
        self.CurrentData = ""
        self.pillcall = ""
        self.pillcallid= ""
        self.vernum = ""

    # Call when an element starts
    def startElement(self, tag, attributes):
        self.CurrentData = tag
        if(tag == "PillCall"):
            print("*****PillCall*****")
            title = attributes["XMLInstanceID"]
            print("XMLInstanceID:=", title) # 想在这里输出多个属性值?
   #        print(sorted()


# create an XMLReader
parser = xml.sax.make_parser()

# turn off namepsaces
parser.setFeature(xml.sax.handler.feature_namespaces, 0)

# override the default ContextHandler
Handler = XMLHandler()
parser.setContentHandler( Handler )
parser.parse("xmltest10.xml")
  • Spyder运行输出:
    *****PillCall*****
    XMLInstanceID:= 98089D9A-768A-4FA0-A7CD-DC5966EB5B06
    
  • PyCharm运行无任何输出

扩展SAX代码(未正常工作)

尝试添加endElement和characters方法,但未达到预期效果:

# Call when an elements ends
def endElement(self, tag):
     if(self.CurrentData != "/PillCall"):
         print("End of PillCall:", self.pillcall)
     elif(self.CurrentData == "PillCallID"):
         print("PillCallID:=", self.pillcallid)
     elif(self.CurrentData == "VersionNumber"):
         print("VersionNumber:=", self.vernum)
     self.CurrentData = ""

# Call when a character is read
def characters(self, content):
     if(self.CurrentData == "PillCall"):
         self.pillcall = content
     elif(self.CurrentData == "qty"):
         self.pillcallid = content
     elif(self.CurrentData == "company"):
         self.vernum = content

需要实现的功能

  1. 完整读取XML中的所有数据(包括PillCall的所有属性)
  2. 循环输出解析得到的数据
  3. 将解析后的数据生成新的XML文件

解决方案

1. 修复SAX解析代码,读取所有属性

PillCall的属性都是元素的属性值,不是子元素文本,无需用characters方法处理。在startElement中直接遍历所有属性即可:

import xml.sax

class XMLHandler(xml.sax.ContentHandler):
    def __init__(self):
        self.current_tag = ""
        self.pillcall_data = []  # 存储所有PillCall的属性数据

    def startElement(self, tag, attributes):
        self.current_tag = tag
        if tag == "PillCall":
            # 读取当前PillCall的所有属性
            pillcall_attrs = {key: attributes[key] for key in attributes.keys()}
            self.pillcall_data.append(pillcall_attrs)
            # 打印当前PillCall的所有属性
            print("*****PillCall*****")
            for key, value in pillcall_attrs.items():
                print(f"{key}:= {value}")

# 初始化解析器
parser = xml.sax.make_parser()
parser.setFeature(xml.sax.handler.feature_namespaces, 0)
handler = XMLHandler()
parser.setContentHandler(handler)
parser.parse("xmltest10.xml")

# 循环输出所有解析到的PillCall数据
print("\n=== 所有PillCall数据 ===")
for idx, data in enumerate(handler.pillcall_data):
    print(f"第{idx+1}条PillCall:")
    for k, v in data.items():
        print(f"  {k}: {v}")

PyCharm无输出问题解决

  • 检查PyCharm运行配置,确保选择了Python 3.8.10解释器
  • 使用XML文件的绝对路径(如C:/project/xmltest10.xml)避免路径错误
  • 查看Run Console是否隐藏,或检查是否有报错信息

2. 基于解析数据生成新XML文件

使用xml.etree.ElementTree生成XML,比SAX更简洁直观:

import xml.etree.ElementTree as ET
from xml.dom import minidom

def generate_xml(pillcall_list, output_path):
    # 创建根节点(根据你的XML结构调整,这里假设根为<PillCalls>)
    root = ET.Element("PillCalls")
    for data in pillcall_list:
        # 创建PillCall元素并添加属性
        pillcall_elem = ET.SubElement(root, "PillCall")
        for key, value in data.items():
            pillcall_elem.set(key, value)
    
    # 格式化XML,输出更美观
    rough_string = ET.tostring(root, 'utf-8')
    reparsed = minidom.parseString(rough_string)
    pretty_xml = reparsed.toprettyxml(indent="  ")
    
    # 写入文件
    with open(output_path, "w", encoding="utf-8") as f:
        f.write(pretty_xml)

# 使用解析得到的数据生成新XML
generate_xml(handler.pillcall_data, "new_pillcalls.xml")

3. 大型文件与并发处理建议

  • SAX是流式解析,天生适合大型XML,无需加载整个文件到内存
  • 并发处理用concurrent.futures.ThreadPoolExecutor(XML解析属于IO密集型任务),数据库操作需用连接池避免频繁创建连接
  • 数据库存储建议用ORM(如SQLAlchemy)简化代码,确保线程安全

内容的提问来源于stack exchange,提问作者WeDoneLost

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 23:55:22