作者:苏木影子Hc_657 | 来源:互联网 | 2024-11-12 16:10
Python 使用 DOM 和 SAX 解析 XML
需求背景:
有一个数据量较大的表,每天需要更新,其字段可以通过 XML 配置文件进行动态配置。每次建表的字段可能会有所不同。
在数据处理过程中,上游系统会根据配置从源文件中提取数据,然后在入库步骤中根据配置创建新的表。
解决方案:
编写一个简单的 XML 配置文件,定义需要的字段及其类型。上游系统读取配置文件中的数据,入库步骤中先删除旧表,再根据配置创建新表。
XML 配置文件示例:
<&#63;xml version="1.0" encoding="UTF-8"&#63;>
id
query
varchar(200)
false
查询内容
pv
integer
false
页面访问量
avg_money
integer
false
平均金额
处理脚本:
#!/usr/bin/python
# -*- coding:utf-8 -*-
# author: wklken
# desc: 用于读取数据库 XML 配置文件
# -----------------------
# 2012-02-18 创建
# ----------------------
import sys, os
from xml.dom import minidom, Node
def read_dbconfig_xml(xml_file_path):
cOntent= {}
root = minidom.parse(xml_file_path)
table = root.getElementsByTagName("table")[0]
# 读取数据库名和表名
table_name = table.getAttribute("name")
db_name = table.getAttribute("db_name")
if len(table_name) > 0 and len(db_name) > 0:
db_sql = f"CREATE DATABASE IF NOT EXISTS `{db_name}`; USE {db_name};"
table_drop_sql = f"DROP TABLE IF EXISTS {table_name};"
content.update({"db_sql": db_sql})
content.update({"table_sql": table_drop_sql})
else:
print(f"Error: attribute not defined properly! db_name={db_name} ;table_name={table_name}")
sys.exit(1)
table_create_sql = f"CREATE TABLE {table_name} ("
# 读取主键
primary_key = table.getElementsByTagName("primary_key")[0]
primary_key_name = primary_key.getElementsByTagName("name")[0].childNodes[0].nodeValue
table_create_sql += f"{primary_key_name} INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,"
# 读取普通字段
fields = table.getElementsByTagName("field")
for field in fields:
name = field.getElementsByTagName("name")[0].childNodes[0].nodeValue
type = field.getElementsByTagName("type")[0].childNodes[0].nodeValue
table_create_sql += f"{name} {type},"
is_index = field.getElementsByTagName("is_index")[0].childNodes[0].nodeValue
table_create_sql = table_create_sql.rstrip(',') + ");"
content.update({"table_create_sql": table_create_sql})
print(content)
if __name__ == "__main__":
read_dbconfig_xml(sys.argv[1])
涉及的方法:
root = minidom.parse(xml_file_path) 获取 DOM 对象
root.getElementsByTagName("table") 获取指定标签的节点列表
table.getAttribute("name") 获取属性值
primary_key.getElementsByTagName("name")[0].childNodes[0].nodeValue 获取子节点的值
SAX 解析
需求背景:
读取大型 XML 数据文件,并实时处理后插入数据库。
XML 文档示例:
100000
男
北京,海淀区
437
1989
333
242
null
大学
1
2月14日
处理思路:
SAX 解析不会像 DOM 一样以节点维度进行读取,而是通过事件驱动的方式处理开始标签、内容和结束标签。
处理代码及注解:
from xml.sax import handler, parseString
class PersonHandler(handler.ContentHandler):
def __init__(self, db_ops):
self.db_ops = db_ops
self.person = {}
self.current_tag = ""
self.in_quote = 0
def startElement(self, name, attrs):
if name == "person":
self.person = {}
self.current_tag = name
self.in_quote = 1
def endElement(self, name):
if name == "person":
in_fields = tuple([f'"{self.person.get(i, "")}"' for i in fields])
print(in_sql % in_fields)
self.db_ops.insert(in_sql % in_fields)
self.in_quote = 0
def characters(self, content):
if self.in_quote:
self.person[self.current_tag] = content
if __name__ == "__main__":
f = open("./person.xml", 'r', encoding='gbk')
db_ops = Db_Connect("127.0.0.1", "root", "root", "test")
parseString(f.read(), PersonHandler(db_ops))
f.close()
db_ops.close()
总结:
本文介绍了如何使用 Python 的 DOM 和 SAX 方法解析 XML 文件,并通过示例展示了如何动态创建数据库表和处理大量数据的实时插入。这些方法在处理大数据和动态配置场景中非常有用。