使用Python解析FineReport模板数据集

 更新时间:2023年12月29日 15:06:03   作者:The_Singing_Towers  
这篇文章主要为大家详细介绍了如何使用Python解析FineReport模板数据集,文中的示例代码讲解详细,具有一定的学习价值,感兴趣的小伙伴可以了解下

背景

在使用 FineReport 作为报表平台过程中,

当报表项目过多,或者报表项目需要迁移,又或者报表数据源需要迁移时,

我们通常需要知道报表用到的表有哪些,或者需要修改的SQL语句有哪些。

这时我们在 FineReport 设计器中需要将模板的数据集提取出来。

但目前设计器中没有 数据集导出 的功能。

所以我们使用Python 开发程式以解析报表模板文件获取 数据集 和 SQL语句,并保存为Excel,

以提供给后续解析SQL获取调用内容的项目使用。

应用场景

  • 查找调用内容
  • FineReport 模板迁移
  • 元数据
  • 数据血缘

操作对象

本示例中使用 本地工作目录 中的 报表模板,FineReport 平台版本为 11

本地工作目录路径

D:\FineReport_11\webapps\webroot\WEB-INF\reportlets

示例报表模板路径

01_dev\record_monitor\record_scheduler.cpt

示例报表模板数据集名称

log_record_execute

示例报表模板数据链接名称

LogDB

示例报表模板截图

解析过程

查找目标模板文件

为保证数据和模板安全,请先下载 正式环境reports文件夹,在本地进行匹配

工作过程中,平台的报表目录不一定之后报表模板文件,故需要用代码先查找匹配,再打开;

代码

import pathlib

# 请先下载 正式环境reports文件夹,在本地进行匹配

work_directory = pathlib.Path("D:\\FineReport_11\\webapps\\webroot\\WEB-INF\\reportlets")

top = pathlib.Path("D:\\FineReport_11\\webapps\\webroot\\WEB-INF\\reportlets\\01_dev\\record_monitor")

# 递归获取 工作目录 本路径和子路径所有扩展名为 .cpt 的 文件
for f in top.rglob("*.cpt"):
    # 模板文件的绝对路径
    abs_path = f.absolute()
    # 为保证对象准确,使用绝对路径
    print(abs_path.__str__())

运行结果

D:\FineReport_11\webapps\webroot\WEB-INF\reportlets\01_dev\record_monitor\record_scheduler.cpt

获取 数据集

FineReport 报表模板 .cpt .frm 本身是 xml 文件,故可直接使用解析XML的方式解析;

解析方式是XPATH语法定位目标元素

代码

import pathlib

from lxml import etree

# 请先下载 正式环境reports文件夹,在本地进行匹配

work_directory = pathlib.Path("D:\\FineReport_11\\webapps\\webroot\\WEB-INF\\reportlets")
top = pathlib.Path("D:\\FineReport_11\\webapps\\webroot\\WEB-INF\\reportlets\\01_dev\\record_monitor")

# 解析结果 收集
result_list = []

# 递归获取 工作目录 本路径和子路径所有扩展名为 .cpt 的 文件
for f in top.rglob("*.cpt"):
    # 模板文件的绝对路径
    abs_path = f.absolute()

    with open(abs_path, mode="rb") as fr:
        xslt_content = fr.read()
    # 开始解析 模板文件 XML
    xml_root = etree.XML(xslt_content)
    # 使用 XPATH 定位 XML 中 数据集内容
    tabel_data_el = xml_root.xpath("//*/TableDataMap//TableData[@class='com.fr.data.impl.DBTableData']")

    for db_data in tabel_data_el:
        # 数据集名称
        date_source_name = db_data.get("name")
        print(date_source_name)

运行结果

log_record_execute

我们可以用 Vs Code 或者其他文本编辑器从资源管理器打开这个模板文件,

可以看到 数据集 在模板XML中的样子,

数据集都在 标签名为 TableDataMap 的 xml 元素下,

数据集本身就是 标签名为 TableData 的 xml 元素,所以使用 XPATH 能够根据这种结构定位到。

同时数据集的内容也能以相同方式定位到。

部分 XML

<?xml version="1.0" encoding="UTF-8"?>
<WorkBook xmlVersion="20211223" releaseVersion="11.0.0">
    <TableDataMap>
        <TableData name="log_record_execute" class="com.fr.data.impl.DBTableData">
            <Parameters>
                <Parameter>
                    <Attributes name="start_date"/>
                    <O>
                        <![CDATA[2023-07-01 00:00:00]]></O>
                </Parameter>
                <Parameter>
                    <Attributes name="end_date"/>
                    <O>
                        <![CDATA[2023-09-07 00:00:00]]></O>
                </Parameter>
            </Parameters>
            <Attributes maxMemRowCount="-1"/>
            <Connection class="com.fr.data.impl.NameDatabaseConnection">
                <DatabaseName>
                    <![CDATA[LogDB]]></DatabaseName>
            </Connection>
            <Query>
                <![CDATA[select * from fine_record_execute where todate(time) >= '${start_date}'  and todate(time) <= '${end_date}']]></Query>
            <PageQuery>
                <![CDATA[]]></PageQuery>
        </TableData>
    </TableDataMap>
    ...
</WorkBook>

获取数据集下的内容

获取到数据集的XML之后,变不需要从整个模板文件定位了,因为数据集的各种内容都在这串XML里了,

所以直接解析 数据集XML 的 字符串就行;

代码

import json
import pathlib

from lxml import etree

# 请先下载 正式环境reports文件夹,在本地进行匹配

work_directory = pathlib.Path("D:\\FineReport_11\\webapps\\webroot\\WEB-INF\\reportlets")
top = pathlib.Path("D:\\FineReport_11\\webapps\\webroot\\WEB-INF\\reportlets\\01_dev\\record_monitor")

# 递归获取 工作目录 本路径和子路径所有扩展名为 .cpt 的 文件
for f in top.rglob("*.cpt"):
    # 模板文件的绝对路径
    abs_path = f.absolute()

    with open(abs_path, mode="rb") as fr:
        xslt_content = fr.read()
    # 开始解析 模板文件 XML
    xml_root = etree.XML(xslt_content)
    # 使用 XPATH 定位 XML 中 数据集内容
    tabel_data_el = xml_root.xpath("//*/TableDataMap//TableData[@class='com.fr.data.impl.DBTableData']")

    for db_data in tabel_data_el:

        # 数据集名称
        date_source_name = db_data.get("name")

        # 转 string 取巧,重新定位数据集内容
        string = etree.tostring(db_data, encoding='utf-8').decode('utf-8')

        data_source = etree.XML(string)
        # 即使 XPATH 定位到的是单个对象,但是返回值是一个list,需要将 list 里的对象 重新拼成 string
        conn = data_source.xpath("/TableData/Connection/DatabaseName/text()")

        conn_collect = []

        for j in conn:
            # 数据链接名字
            conn_collect.append(str(j).strip())

        conn_string = "".join(conn_collect)

        query = data_source.xpath("/TableData/Query/text()")

        query_collect = []

        for j in query:
            # 数据集SQL
            query_collect.append(str(j).strip())

        query_string = "".join(query_collect)

        # 将 解析结果 拼接到 dict
        data_source_json = {
            "report": pathlib.Path.relative_to(abs_path, work_directory).__str__(),
            "data_source": date_source_name,
            "conn": conn_string,
            "query": query_string
        }

        print(json.dumps(data_source_json, ensure_ascii=False))

运行结果

{
    "report": "01_dev\\record_monitor\\record_scheduler.cpt",
    "data_source": "log_record_execute",
    "conn": "LogDB",
    "query": "select * from fine_record_execute where todate(time) >= '${start_date}'  and todate(time) <= '${end_date}'"
}

可以看到,报表模板路径,数据集名称,数据链接名称,SQL语句都完整获取到了。

完整代码

最后将获取到的内容转成 pandas 的 DataFrame,然后输出到Excel

import pathlib

import pandas as pd
from lxml import etree

# 请先下载 正式环境reports文件夹,在本地进行匹配

work_directory = pathlib.Path("D:\\FineReport_11\\webapps\\webroot\\WEB-INF\\reportlets")
top = pathlib.Path("D:\\FineReport_11\\webapps\\webroot\\WEB-INF\\reportlets\\01_dev\\record_monitor")

# 解析结果 收集
result_list = []
# fineReport .cpt .frm 本身是xml文件,故可直接按行匹配字符查找是否与对象有关
# 递归获取 工作目录 本路径和子路径所有扩展名为 .cpt 的 文件
for f in top.rglob("*.cpt"):
    # 模板文件的绝对路径
    abs_path = f.absolute()

    with open(abs_path, mode="rb") as fr:
        xslt_content = fr.read()
    # 开始解析 模板文件 XML
    xml_root = etree.XML(xslt_content)
    # 使用 XPATH 定位 XML 中 数据集内容
    tabel_data_el = xml_root.xpath("//*/TableDataMap//TableData[@class='com.fr.data.impl.DBTableData']")

    for db_data in tabel_data_el:

        # 数据集名称
        date_source_name = db_data.get("name")

        # 转 string 取巧,重新定位数据集内容
        string = etree.tostring(db_data, encoding='utf-8').decode('utf-8')

        data_source = etree.XML(string)
        # 即使 XPATH 定位到的是单个对象,但是返回值是一个list,需要将 list 里的对象 重新拼成 string

        conn = data_source.xpath("/TableData/Connection/DatabaseName/text()")

        conn_collect = []

        for j in conn:
            # 数据链接名字
            conn_collect.append(str(j).strip())

        conn_string = "".join(conn_collect)

        query = data_source.xpath("/TableData/Query/text()")

        query_collect = []

        for j in query:
            # 数据集SQL
            query_collect.append(str(j).strip())

        query_string = "".join(query_collect)

        # 将 解析结果 拼接到 dict
        data_source_json = {
            "report": pathlib.Path.relative_to(abs_path, work_directory).__str__(),
            "data_source": date_source_name,
            "conn": conn_string,
            "query": query_string
        }

        result_list.append(data_source_json)

df = pd.DataFrame(result_list)

df.to_excel("./data_source.xlsx", engine="openpyxl", index=False)

运行结果

到此这篇关于使用Python解析FineReport模板数据集的文章就介绍到这了,更多相关Python解析FineReport数据集内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • pandas按某列降序的实现

    pandas按某列降序的实现

    本文主要介绍了pandas按某列降序的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-01-01
  • Python图像处理库PIL的ImageDraw模块介绍详解

    Python图像处理库PIL的ImageDraw模块介绍详解

    这篇文章主要介绍了Python图像处理库PIL的ImageDraw模块介绍详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-02-02
  • 详解pycharm连接远程linux服务器的虚拟环境的方法

    详解pycharm连接远程linux服务器的虚拟环境的方法

    这篇文章主要介绍了pycharm连接远程linux服务器的虚拟环境的详细教程,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-11-11
  • python读写删除复制文件操作方法详细实例总结

    python读写删除复制文件操作方法详细实例总结

    这篇文章主要介绍了python读写删除复制文件操作方法详细实例总结,需要的朋友可以参考下
    2021-04-04
  • Python堆栈的具体使用

    Python堆栈的具体使用

    本文主要介绍了Python堆栈的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-11-11
  • 教你如何在Pygame 中移动你的游戏角色

    教你如何在Pygame 中移动你的游戏角色

    Pygame是一组跨平台的 Python 模块,专为编写视频游戏而设计,您可以使用 pygame 创建不同类型的游戏,包括街机游戏、平台游戏等等,今天通过本文给大家介绍Pygame移动游戏角色的实现过程,一起看看吧
    2021-09-09
  • 基于PyQt5制作一个windows通知管理器

    基于PyQt5制作一个windows通知管理器

    python框架win10toast可以用来做windows的消息通知功能,通过设定通知的间隔时间来实现一些事件通知的功能。本文将利用win10toast这一框架制作一个windows通知管理器,感兴趣的可以参考一下
    2022-02-02
  • python实现与Oracle数据库交互操作示例

    python实现与Oracle数据库交互操作示例

    这篇文章主要为大家介绍了python实现与Oracle数据库交互操作示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家,多多进步,早日升职加薪
    2021-10-10
  • Python使用pip安装报错:is not a supported wheel on this platform的解决方法

    Python使用pip安装报错:is not a supported wheel on this platform的解决

    这篇文章主要介绍了Python使用pip安装报错:is not a supported wheel on this platform的解决方法,结合实例形式分析了在安装版本正确的情况下pip安装报错的原因与相应的解决方法,需要的朋友可以参考下
    2018-01-01
  • Python 图片文字识别的实现之PaddleOCR

    Python 图片文字识别的实现之PaddleOCR

    OCR方向的工程师,之前一定听说过PaddleOCR这个项目,其主要推荐的PP-OCR算法更是被国内外企业开发者广泛应用,短短半年时间,累计Star数量已超过15k,频频登上Github Trending和Paperswithcode 日榜月榜第一
    2021-11-11

最新评论