示例页面

python 解析帆软cpt文件

1、解析cpt文件

遇到需要对帆软 cpt / frm 文件内的查询语句中用到的库表进行提取的工作,以便仅同步迁移相应库表数据。cpt / frm 格式的文件是帆软报表中特有的数据文件格式,在进行数据报表迁移时,通过导出相应目录资源,即可获得一个压缩包,这个压缩包里包含了两个json文件和一个frReport文件夹,需要解析的库表名称则位于 frReport 文件夹内的子文件夹中。

image

用本地文本编辑器打开一个cpt格式文件,大概内容如下:

image

可以看到这是一种 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)

image

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
posted @ 2023-06-26 15:38  没有风格的Wang  阅读(620)  评论(0编辑  收藏  举报