python 解析帆软cpt文件
1、解析cpt文件
遇到需要对帆软 cpt / frm 文件内的查询语句中用到的库表进行提取的工作,以便仅同步迁移相应库表数据。cpt / frm 格式的文件是帆软报表中特有的数据文件格式,在进行数据报表迁移时,通过导出相应目录资源,即可获得一个压缩包,这个压缩包里包含了两个json文件和一个frReport文件夹,需要解析的库表名称则位于 frReport 文件夹内的子文件夹中。
用本地文本编辑器打开一个cpt格式文件,大概内容如下:
可以看到这是一种 xml 语言,在使用python进行数据解析时,需要用到xml.etree.ElementTree 模块解析。
完整脚本如下:
import pandas as pd # pip install pypiwin32 / pywin32 # import win32com.client as win32 仅支持 windows 系统 import xml.etree.ElementTree as ET import os import re # 保存待处理的文件夹路径 def read_files_in_directory(directory): stack = [directory] # 使用栈来保存待处理的文件夹路径 file_paths = [] while stack: current_dir = stack.pop() # 移除并返回列表中的最后一个元素 for entry in os.scandir(current_dir): # 用于从指定的文件夹中获取包含文件和子文件夹的迭代器 if entry.is_file(): # 处理文件 # print("File:", entry.path) file_paths.append(entry.path) # stack.append(entry.path) elif entry.is_dir(): # 处理子文件夹,将子文件夹路径加入栈中 # print("Directory:", entry.path) stack.append(entry.path) return file_paths # 文件夹路径 cpt_path = '/Users/测评文件/帆软报表脚本/待解析脚本' # 获取帆软报表指定格式文件 cpt_file = [f for f in read_files_in_directory(cpt_path) if f.endswith(('.cpt','.frm'))] database_table_pairs = [] # 用来存放库、表名称 for file_dir in cpt_file: with open(file_dir, "r") as file: xml_content = file.read() root = ET.fromstring(xml_content) for database in root.iter("DatabaseName"): database_name = database.text.strip() # 数据库名称 # i = 0 for element in root.iter("Query"): code = element.text.lower().strip() # 转换为小写 # print(code) # i = i+1 # print(i) words = code.split() for i in range(len(words)): if words[i] == "from" and words[i+1] not in [" ", "\n", "\t", "(", "(select"]: table_name = words[i+1].split(")")[0] # 获取 from 关键字后的单词作为表名称 database_table_pairs.append((database_name, table_name)) if words[i] == 'join' and words[i+1] not in [" ", "\n", "\t", "(", "(select"]: table_name = words[i+1].split(")")[0] database_table_pairs.append((database_name, table_name)) # 列表数据去重 database_table = list(set(database_table_pairs)) # 保存输出结果到本地 df = pd.DataFrame(database_table, columns=['db_name', 'table_name']) df.to_excel('/Users/测评文件/帆软报表脚本/0619-解析库表.xlsx', index=False)
2、mysql库表适配达梦
批量修改查询脚本适配达梦数据库
# 找出所有 mysql 文件 cpt_path = '/Users/测评文件/帆软报表脚本/待解析脚本' cpt_file = [f for f in read_files_in_directory(cpt_path) if f.endswith(('.cpt','.frm'))] mysql_cpt_file = [] for file_dir in cpt_file: with open(file_dir, "r") as file: xml_content = file.read() root = ET.fromstring(xml_content) for database in root.iter("DatabaseName"): database_name = database.text.strip().lower() if database_name in ('174mysql_rt' , '174mysql'): mysql_cpt_file.append(file_dir) # print(mysql_cpt_file)
# 创建列表: 01 中过滤出的 mysql 库表 schema_name = 'dameng' mysql_table_name = [ 'table_name_01', 'table_name_02']
for file_dir in mysql_cpt_file: # for file_dir in ['/Users/测评文件/帆软报表脚本/待解析脚本/综合展示/frReport/4e38a84c-0f27-4757-aeb1-1f878909c81c/Analysis/大屏V4.6.frm']: # 获取文件路径中 倒数两个文件名称 file_name_01 = file_dir.rfind("/") + 1 file_name_02 = file_dir.rfind("/", 0, file_name_01-1) + 1 file_name_03 = file_dir[file_name_02:] with open(file_dir, "r") as file: xml_content = file.read() root = ET.fromstring(xml_content) # 获取查询数据集名称 for element in root.iter("TableData"): name = element.attrib.get("name") abb_name = name.lower().strip() if name is not None else None # 获取查询数据库名称 for database in element.iter("DatabaseName"): database_name = database.text.lower().strip() if database_name in ('174mysql_rt' , '174mysql'): # 修改查询语句中的语法 for query in element.iter("Query"): code_01 = query.text.lower().strip() # 转换为小写 code_02 = code_01.replace('"', "'").replace('`', '').replace('%y', '%Y') code_03 = code_02.replace('date_sub', 'add_days').replace('interval 1 day', '-1') words = code_03.split() # 判断查询语句中的表是否为目标 mysql 表 for table_name in mysql_table_name: for i in range(len(words)): if words[i] in['from', 'join'] and words[i+1] not in [" ", "\n", "\t", "(", "(select"]: extract_table = words[i+1].split(")")[0] # 获取 from 关键字后的单词作为表名称 if extract_table == table_name: db_table_name = f"{schema_name}.{extract_table}" sub_code = re.sub(extract_table, db_table_name, code_03) print('----------------------------------') print('文件名称:', file_name_03) print('----------------------------------') print("表别名是:", abb_name) print('----------------------------------') print("数据库名是:", database_name) print('----------------------------------') print(sub_code) print('----------------------------------') # break
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)