python解析帆软cpt及frm文件(xml)获取源数据表及下游依赖表

#!/user/bin/evn python
import os,re,openpyxl
'''
    输入:帆软脚本文件路径
    输出:帆软文件检查结果Excel
'''
#获取来源表
def table_scan(sql_str):
    # remove the /* */ comments

    q = re.sub(r"/\*[^*]*\*+(?:[^*/][^*]*\*+)*/", "", sql_str)
    # remove whole line -- and # comments
    lines = [line for line in q.splitlines() if not re.match("^\s*(--|#)", line)]

    # remove trailing -- and # comments
    q = " ".join([re.split("--|#", line)[0] for line in lines])

    # split on blanks, parens and semicolons
    tokens = re.split(r"[\s)(;]+", q)

    # scan the tokens. if we see a FROM or JOIN, we set the get_next
    # flag, and grab the next one (unless it's SELECT).

    result = []
    get_next = False
    for token in tokens:
        if get_next:
            if token.lower() not in ["", "select"]:
                #过滤掉因条件设置选择来源表而产生的脏数据非表名字符
                if '"+if' not in token and '"'not in token and '$if' not in token and '${if' not in token:
                    result.append(token.replace('`',''))
            get_next = False
        get_next = token.lower() in ["from", "join"]
    #特殊单独情况处理:from后面来源表条件选择对应来源表,比如from ${if(XX,"来源表A","来源表B")}
    # print(result)
    if not result:
        tab_pat=re.compile(r'from.*?if\((.*?)\)',re.S)
        for i in re.findall(tab_pat,sql_str):
            temp_r=i.replace('"','').split(',')
            if '' not in temp_r and '/*' not in temp_r:
                result.append(temp_r[1].replace('`','').strip())
                result.append(temp_r[2].replace('`','').strip())
    return result

#文件扫描,使用正则解析第一版,准确性不太高!
def file_scan(path):
    f_content=open(path,'r',encoding='utf-8').read()

    #1、数据集查询
    sqlgpat=re.compile('<TableDataMap>(.*?)</TableDataMap>',re.S)
    if_has_sqlg=re.findall(sqlgpat,f_content)
    rs_sql_list=[]
    if if_has_sqlg:
        #获取数据集名称以及数据集查询语句
        sqlspat=re.compile('<TableData name="(.*?)".*?<DatabaseName>\n<!\[CDATA\[(.*?)]]></DatabaseName>.*?<Query>\n<!\[CDATA\[(.*?)]]></Query>.*?</TableData>',re.S)
        rs1=re.findall(sqlspat,if_has_sqlg[0])
        for rsv in rs1:
            from_tables=[]
            if '"*/"' in rsv[1]:
                sql=rsv[1].split('*/')
                for ss in sql:
                    from_tables.extend(table_scan(ss))
            else:
                from_tables.extend(table_scan(rsv[2]))
            rs_sql_list.append([rsv[0],rsv[1],rsv[2],set(from_tables)])
            # print(rsv[1])

    #2、js获取
    if_has_jsgpat=re.compile('<NameJavaScript name="(.*?)</NameJavaScript>',re.S)
    if_has_jsg=re.findall(if_has_jsgpat, f_content)
    rep_list = []  # 报表列表,去重
    if if_has_jsg:
        for jscon in if_has_jsg:
            # conturlpat=re.compile('<Content>.*?var\surl\s=.*?viewlet=(.*?.[cptfrm]{3})&.*?</Content>',re.S)
            conturlpat = re.compile('<Content>.*?viewlet=(.*?[cptfrm]{3})[&?].*?</Content>', re.S)

            if '<JavaScript class="com.fr.js.ReportletHyperlink">' in jscon:
                # rlpat=re.compile('<ReportletName extendParameters="true" showPI="true">\s<!\[CDATA\[(.*?)]]></ReportletName>',re.S)
                rlpat = re.compile( '<ReportletName .*?\[CDATA\[(.*?)]]></ReportletName>', re.S)

                rl=re.findall(rlpat,jscon)[0]
                # print(re.findall(rlpat,jscon))
                if rl not in rep_list:
                    rep_list.append(rl)
            elif '<JavaScript class="com.fr.js.WebHyperlink">' in jscon:
                wlpat=re.compile('<URL>\s<!\[CDATA\[(.*?)]]></URL>',re.S)
                wl=re.findall(wlpat,jscon)[0]
                if wl not in rep_list:
                    rep_list.append(wl)
            elif re.search(conturlpat,jscon):
                frl=re.findall(conturlpat,jscon)[0]
                print(frl)
                if not frl.startswith('/'):
                    frl='/'+frl
                if frl not in rep_list:
                    rep_list.append(frl)
            # elif '<JavaScript class="com.fr.js.JavaScriptImpl">'in jscon and('.cpt' in jscon or '.frm' in jscon) :
            #     print(jscon)

    if_has_cljpat=re.compile(r'<RHIframeSource.*?<Attr path="(.*?[cptfrm]{3}).*?</RHIframeSource>',re.S)
    f_has_clj=re.findall(if_has_cljpat,f_content)
    if f_has_clj:
        for v in f_has_clj:
            if v not in rep_list:
                rep_list.append(v)
    # print(rep_list)
    return rep_list,rs_sql_list

#使用xml解析精准获取
def xml_scan(path):
    import xml.etree.ElementTree as ET
    tree = ET.parse(path)  # 打开xml文件

    dataset_iters = []  # 数据集名称,数据集数据库链接名,数据集查询语句,数据集来源sql表
    if list(tree.getroot().iter("TableDataMap")):
        # 数据集TableDataMap父节点
        table_map_content = list(tree.getroot().iter("TableDataMap"))[0]
        # 获取数据集查询名称
        dataset_iters_map = table_map_content.iter('TableData')
        for val in dataset_iters_map:
            # print('查询名称--',val.attrib.get("name"))
            dataset_name = val.attrib.get("name").strip()
            if len(list(val.iter("DatabaseName"))):
                # 帆软目前一个数据集查询框只能链接单个数据库,所以获取数据库链接名只有1个
                # print('查询数据库链接名--', list(val.iter("DatabaseName"))[0].text.strip())
                dataset_connect_name = list(val.iter("DatabaseName"))[0].text.strip()
            else:
                # print('查询数据库链接名--',None)
                dataset_connect_name = None
            if len(list(val.iter("Query"))):
                # 帆软目前一个数据集查询框只能链接单个数据库,所以获取数据库链接名只有1个,且只有一个sql查询窗口内容
                # print('查询数据查询语句--', list(val.iter("Query"))[0].text.strip())
                dataset_query = list(val.iter("Query"))[0].text.strip()
                from_tables = []
                if '"*/"' in dataset_query:
                    sql = dataset_query.split('*/')
                    for ss in sql:
                        # print(ss)
                        from_tables.extend(table_scan(ss))
                else:
                    from_tables.extend(table_scan(dataset_query))

            else:
                # print('查询数据查询语句--', None)
                dataset_query = None
                from_tables=[]
            dataset_iters.append([dataset_name, dataset_connect_name, dataset_query,from_tables])

    urls = set()  # 报表全体下游调用URL集合
    js_contents = []  # js内容,内容清洗出来的URL,用于核对数据清洗是否准确

    # print(len(list(tree.iter("ReportletName"))))#js链接报表-网格报表-本地服务器
    local_url = [v.text.strip() for v in tree.iter("ReportletName")]
    if local_url:
        urls.update(local_url)

    # print(len(list(tree.iter("URL"))))  # js链接报表-网格报表-远程web链接
    web_url = [v.text.strip() for v in tree.iter("URL")]
    if web_url:
        urls.update(web_url)

    # print(len(list(val.iter("RHIframeSource"))))# js链接报表-tab框架挂载报表
    for v in tree.iter("RHIframeSource"):
        webframe_url = list(v.iter("Attr"))[0].attrib.get("path")
        # 去除URL尾巴参数
        if webframe_url and not webframe_url.endswith("frm") and not webframe_url.endswith("cpt"):

            rpat = re.compile(r'.*?[cptfrm]{3}', re.I)
            webframe_url = re.findall(rpat, webframe_url)[0]
            urls.update([webframe_url])
        elif webframe_url:
            urls.update([webframe_url])

            # print(len(list(val.iter("Content"))))
    for cv in list(tree.iter("Content")):
        contents = cv.text
        temp_url = []
        # print(contents)
        http_ul_pat = re.compile(r'"(http.*?)"') #js内容里面挂载web超链接
        local_ul_pat = re.compile(r'viewlet=(.*?[cptfrm]{3})')#js内容里面挂载服务器本地绝对路径报表链接
        # print(re.findall(http_ul_pat,contents))
        # print(re.findall(local_ul_pat, contents))
        if re.findall(http_ul_pat, contents):
            urls.update(re.findall(http_ul_pat, contents))
            temp_url.extend(re.findall(http_ul_pat, contents))


        if re.findall(local_ul_pat, contents):
            # print(re.findall(local_ul_pat, contents))
            #处理挂载服务器本地链接路径,有些挂载绝对目录不规范a/b/c.cpt处理后输出/a/b/c.cpt
            for vl in re.findall(local_ul_pat, contents):
                if vl.startswith('/'):
                    urls.update([vl])
                    temp_url.append(vl)
                else:
                    urls.update(['/'+vl])
                    temp_url.append('/'+vl)

        js_contents.append([contents, temp_url])
    # print(js_contents)
    return dataset_iters,urls,js_contents

def write_excel(list_tar,file_path):
    wb = openpyxl.Workbook()  # 新建工作簿
    sheet0=wb[wb.sheetnames[0]]
    sheet0.title=('引用报表列表')
    sheet1 = wb.create_sheet('来源mysql表')
    sheet2 = wb.create_sheet('帆软数据集查询及依赖明细')
    sheet3 = wb.create_sheet('帆软JS内容明细')

    sheet0['A1'] = '文件名'
    sheet0['B1'] = '依赖报表'
    sheet1['A1'] = '文件名'
    sheet1['B1'] = '依赖mysql表'

    sheet2['A1'] = '文件名'
    sheet2['B1'] = '数据集查询名称'
    sheet2['C1'] = '数据库链接名称'
    sheet2['D1'] = '数据集查询语句'
    sheet2['E1'] = '数据来源mysql表'

    sheet3['A1'] = '文件名'
    sheet3['B1'] = 'JS内容'
    sheet3['C1'] = 'JS解析URL'

    r=1
    k=1
    d=1
    x=1
    for index,item in enumerate(list_tar):
        print(('开始处理第 '+str(index+1)+' 个文件结果,共 '+str(len(list_tar))+' 个').center(50,'-'))
        # filename,dataset_iters, urls, js_contents
        # dataset_iters = []  # 数据集名称,数据集数据库链接名,数据集查询语句,数据集来源sql表
        target_file_name=item[0]
        cpt=item[2]
        sql=item[1]
        jsc=item[3]

        for id1,value in enumerate(sorted(cpt)):
            r=r+1
            sheet0.cell(row=r, column=1, value=target_file_name)
            sheet0.cell(row=r, column=2, value=value)

        sql_set=set()
        for id1,val in enumerate(sql):
            k = k + 1
            sql_set.update(val[3])
            sheet2.cell(row=k, column=1, value=target_file_name)
            sheet2.cell(row=k, column=2, value=val[0])
            sheet2.cell(row=k, column=3, value=val[1])
            sheet2.cell(row=k, column=4, value=val[2])
            sheet2.cell(row=k, column=5, value='\n'.join(val[3]))

        for id1,value in enumerate(sorted(sql_set)):
            d = d + 1
            sheet1.cell(row=d, column=1, value=target_file_name)
            sheet1.cell(row=d, column=2, value=value)

        for id1, value in enumerate(sorted(jsc)):
            if value[0] or value[1]:
                x = x +1
                sheet3.cell(row=x, column=1, value=target_file_name)
                sheet3.cell(row=x, column=2, value=value[0])
                sheet3.cell(row=x, column=3, value='\n'.join(value[1]))

    wb.save(file_path)
    wb.close() # excel使用完成需要关闭,否则会报错

def main_scan(fr_path,result_path):
    rs_list=[]
    file_list=[]
    file_name=[]
    for dirpath, dirnames, filenames in os.walk(fr_path):
        for file in filenames:
            file_list.append(os.path.join(dirpath,file))
            file_name.append(os.path.join(dirpath,file).replace(r'【清空前缀:本地机扫描文件夹绝对路径】','').replace('\\','/'))
    for index,file in enumerate(file_list):
        print(('正在扫描第 '+str(index+1)+' 个文件,共 '+str(len(file_list))+' 个文件').center(50,'-'))
        try:
            dataset_iters,urls,js_contents = xml_scan(file)
            rs_list.append([file_name[index],dataset_iters,urls,js_contents])
        except:
            print('【文件扫描失败】:',file)
    print('文件扫描完毕,正在写入Excel'.ljust(50,'-'))
    write_excel(rs_list, result_path)


if __name__ == '__main__':
    #帆软扫描文件夹绝对路径
    fr_path=r'【本地机扫描文件夹绝对路径】'

    #帆软扫描结果文件绝对路径
    result_path=r'【本地机结果路径】\scaning_result.xlsx'
    main_scan(fr_path, result_path)

扫描文件夹:

运行结果

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/59573.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

探索硬件王国:计算机硬件信息一览(使用powershell获得计算机硬件信息)

获得运行权限&#xff1a; 请确保在运行脚本文件之前&#xff0c;设置了适当的执行策略。如果需要&#xff0c;可以使用 Set-ExecutionPolicy 命令更改执行策略。例如&#xff0c;可以使用以下命令将执行策略设置为 RemoteSigned&#xff1a; Set-ExecutionPolicy RemoteSign…

云真机调研

1. 主流云真机 目前市面上主流的远程真机服务商有:Testin云测、百度MTC、TestBird、精灵云测、腾讯Wetest、泽众云等,设备上基本覆盖Android、iOS和鸿蒙等主流设备,通过远程真机可以进行手工测试、代码调试、自动化脚本录制及执行等 2. testin 登录-云测&#xff0c;助力产业…

通用指令(汇编)

一、数据处理指令1&#xff09;数学运算数据运算指令的格式数据搬移指令立即数伪指令加法指令带进位的加法指令减法指令带借位的减法指令逆向减法指令乘法指令数据运算指令的扩展 2&#xff09;逻辑运算按位与指令按位或指令按位异或指令左移指令右移指令位清零指令 3&#xff…

【枚举+trie+dfs】CF514 C

Problem - 514C - Codeforces 题意&#xff1a; 思路&#xff1a; 其实是trie上dfs的板题 先把字符串插入到字典树中 对于每次询问&#xff0c;都去字典树上dfs 注意到字符集只有3&#xff0c;因此如果发现有不同的字符&#xff0c;去枚举新的字符 Code&#xff1a; #in…

学习单片机的秘诀:实践与坚持

在学习单片机时&#xff0c;将实践与学习结合起来是一个很好的方法。不要一上来就死磕指令和名词&#xff0c;而是边学边做实验&#xff0c;循序渐进地理解和应用指令。通过实验&#xff0c;你能亲身感受到指令的控制效果&#xff0c;增强对单片机的理解和兴趣。 学习单片机不…

【iOS】App仿写--天气预报

文章目录 前言一、首页二、搜索界面三、添加界面四、浏览界面总结 前言 最近完成了暑假的最后一个任务——天气预报&#xff0c;特此记录博客总结。根据iPhone中天气App的功能大致可以将仿写的App分为四个界面——首页&#xff0c;搜索界面&#xff0c;添加界面&#xff0c;浏…

dflow工作流使用1——架构和基本概念

对于容器技术、工作流等概念完全不懂的情况下理解dflow的工作方式会很吃力&#xff0c;这里记录一下个人理解。 dflow涉及的基本概念 工作流的概念很好理解&#xff0c;即某个项目可以分为多个步骤&#xff0c;每个步骤可以实现独立运行&#xff0c;只保留输入输出接口&#x…

WebGL Shader着色器GLSL语言

在2D绘图中的坐标系统&#xff0c;默认情况下是与窗口坐标系统相同&#xff0c;它以canvas的左上角为坐标原点&#xff0c;沿X轴向右为正值&#xff0c;沿Y轴向下为正值。其中canvas坐标的单位都是’px’。 WebGL使用的是正交右手坐标系&#xff0c;且每个方向都有可使用的值的…

c语言野指针int*p、空指针int*p = NULL、万能指针void* p

1、野指针&#xff0c;既没有初始化的指针&#xff0c;//如果没有给指针初始化&#xff0c;则指针p的内容为随机地址&#xff0c;会随机指向&#xff0c;故成为野指针&#xff0c;不可以操作野指针 #include "stdio.h" #include <stdlib.h>int main() {//1、野…

ORACLE常用基础

. 1.oracle开机启动流程 su - oracle lsnrctl start lsnrctl status sqlplus / as sysdba startup 2、如何查看数据库版本 select * from v$version; 3.如何查看用户从那个设备连接的数据库 SELECT DISTINCT machine , terminal FROM V$SESSION; 4.如何查看表结构 selec…

FANUC机器人SRVO-300机械手断裂故障报警原因分析及处理办法

FANUC机器人SRVO-300机械手断裂故障报警原因分析及处理办法 首先,我们查看报警说明书上的介绍: 总结:即在机械手断裂设置为无效时,机器人检测出了机械手断裂信号(不该有的信号,现在检测到了,所以报警) 使机械手断裂设定为无效/有效的具体方法:  按下示教器的MENU菜单…

Vue前端框架入门

文章目录 Vue快速入门Vue指令生命周期 Vue 经过一小段时间学习 我认为vue就是在原js上进行的一个加强 简化JS中的DOM操作 vue是分两个层的 一个叫做视图层(View)&#xff0c;你可以理解为展现出来的前端页面 一个叫数据模型层(Model),包含数据和一些数据的处理方法 MVVM就是实…

数据结构10 -查找_树表查找

创建二叉搜索树 二叉搜索树 二叉搜索树是有数值的了&#xff0c;二叉搜索树是一个有序树。 若它的左子树不空&#xff0c;则左子树上所有结点的值均小于它的根结点的值&#xff1b; 若它的右子树不空&#xff0c;则右子树上所有结点的值均大于它的根结点的值&#xff1b; 它…

从0到1开发go-tcp框架【2-实现Message模块、解决TCP粘包问题、实现多路由机制】

从0到1开发go-tcp框架【2-实现Message模块、解决TCP粘包问题、实现多路由机制】 1 实现\封装Message模块 zinx/ziface/imessage.go package zifacetype IMessage interface {GetMsdId() uint32GetMsgLen() uint32GetMsgData() []byteSetMsgId(uint32)SetData([]byte)SetData…

组合总和——力扣39

文章目录 题目描述回溯 题目描述 回溯 class Solution { public:vector<vector<int>> res;vector<int> seq; void dfs(vector<int>& nums, int pos, int target){if(target0){res.emplace_back(seq);return;}if(posnums.size()){return;}//直接跳过…

2023上半年手机及数码行业分析报告(京东销售数据分析)

2023年上半年&#xff0c;手机市场迎来复苏&#xff0c;同环比来看&#xff0c;销量销额纷纷上涨。 而数码市场中&#xff0c;各个热门品类表现不一。微单相机及智能手表同比去年呈现增长态势&#xff0c;而笔记本电脑市场则出现下滑。 基于此现状&#xff0c;鲸参谋发布了20…

Ubuntu 虚拟机和主机无法互相复制文字和文件

1.在虚拟机列表中&#xff0c;右键查看是否有安装VMware Tools&#xff0c;如果没有安装点击安装&#xff0c;如果已经安装了&#xff0c;上面显示重现安装VMware Tools&#xff0c;并且为灰色&#xff0c;如图&#xff1a; 2.如果没有安装点击安装&#xff0c;如果已经安装&am…

【知识产权】专利的弊端

接上篇【知识产权】著作权的作用_qilei2010的博客-CSDN博客。 ​ 1 专利的分类 首先,专利分为:发明专利、实用新型专利、外观设计专利。这里要说明的是专利的不同种类在不同的国家都是有不同规定的,并不是所有国家和地区都是分成这三类。 >国家法律法规数据库 >中华…

untiy代码打压缩包,可设置密码

1、简单介绍&#xff1a; 用的是一个插件SharpZipLib&#xff0c;在vs的Nuget下载&#xff0c;也可以去github下载https://github.com/icsharpcode/SharpZipLib 用这个最主要的是因为&#xff0c;这个不用请求windows的文件读写权限&#xff0c;关于这个权限我搞了好久&#…

51单片机(普中HC6800-EM3 V3.0)实验例程软件分析 实验四 蜂鸣器

目录 前言 一、原理图及知识点介绍 1.1、蜂鸣器原理图&#xff1a; 二、代码分析 前言 第一个实验:51单片机&#xff08;普中HC6800-EM3 V3.0&#xff09;实验例程软件分析 实验一 点亮第一个LED_ManGo CHEN的博客-CSDN博客 第二个实验:51单片机&#xff08;普中HC6800-EM…