使用Python解析FineReport模板數(shù)據(jù)集
背景
在使用 FineReport 作為報表平臺過程中,
當報表項目過多,或者報表項目需要遷移,又或者報表數(shù)據(jù)源需要遷移時,
我們通常需要知道報表用到的表有哪些,或者需要修改的SQL語句有哪些。
這時我們在 FineReport 設(shè)計器中需要將模板的數(shù)據(jù)集提取出來。
但目前設(shè)計器中沒有 數(shù)據(jù)集導(dǎo)出 的功能。
所以我們使用Python 開發(fā)程式以解析報表模板文件獲取 數(shù)據(jù)集 和 SQL語句,并保存為Excel,
以提供給后續(xù)解析SQL獲取調(diào)用內(nèi)容的項目使用。
應(yīng)用場景
- 查找調(diào)用內(nèi)容
- FineReport 模板遷移
- 元數(shù)據(jù)
- 數(shù)據(jù)血緣
操作對象
本示例中使用 本地工作目錄 中的 報表模板,F(xiàn)ineReport 平臺版本為 11
本地工作目錄路徑
D:\FineReport_11\webapps\webroot\WEB-INF\reportlets
示例報表模板路徑
01_dev\record_monitor\record_scheduler.cpt
示例報表模板數(shù)據(jù)集名稱
log_record_execute
示例報表模板數(shù)據(jù)鏈接名稱
LogDB
示例報表模板截圖
解析過程
查找目標模板文件
為保證數(shù)據(jù)和模板安全,請先下載 正式環(huán)境reports文件夾,在本地進行匹配
工作過程中,平臺的報表目錄不一定之后報表模板文件,故需要用代碼先查找匹配,再打開;
代碼
import pathlib # 請先下載 正式環(huán)境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__())
運行結(jié)果
D:\FineReport_11\webapps\webroot\WEB-INF\reportlets\01_dev\record_monitor\record_scheduler.cpt
獲取 數(shù)據(jù)集
FineReport 報表模板 .cpt .frm 本身是 xml 文件,故可直接使用解析XML的方式解析;
解析方式是XPATH語法定位目標元素
代碼
import pathlib from lxml import etree # 請先下載 正式環(huán)境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") # 解析結(jié)果 收集 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 中 數(shù)據(jù)集內(nèi)容 tabel_data_el = xml_root.xpath("http://*/TableDataMap//TableData[@class='com.fr.data.impl.DBTableData']") for db_data in tabel_data_el: # 數(shù)據(jù)集名稱 date_source_name = db_data.get("name") print(date_source_name)
運行結(jié)果
log_record_execute
我們可以用 Vs Code 或者其他文本編輯器從資源管理器打開這個模板文件,
可以看到 數(shù)據(jù)集 在模板XML中的樣子,
數(shù)據(jù)集都在 標簽名為 TableDataMap 的 xml 元素下,
數(shù)據(jù)集本身就是 標簽名為 TableData 的 xml 元素,所以使用 XPATH 能夠根據(jù)這種結(jié)構(gòu)定位到。
同時數(shù)據(jù)集的內(nèi)容也能以相同方式定位到。
部分 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>
獲取數(shù)據(jù)集下的內(nèi)容
獲取到數(shù)據(jù)集的XML之后,變不需要從整個模板文件定位了,因為數(shù)據(jù)集的各種內(nèi)容都在這串XML里了,
所以直接解析 數(shù)據(jù)集XML 的 字符串就行;
代碼
import json import pathlib from lxml import etree # 請先下載 正式環(huán)境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 中 數(shù)據(jù)集內(nèi)容 tabel_data_el = xml_root.xpath("http://*/TableDataMap//TableData[@class='com.fr.data.impl.DBTableData']") for db_data in tabel_data_el: # 數(shù)據(jù)集名稱 date_source_name = db_data.get("name") # 轉(zhuǎn) string 取巧,重新定位數(shù)據(jù)集內(nèi)容 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: # 數(shù)據(jù)鏈接名字 conn_collect.append(str(j).strip()) conn_string = "".join(conn_collect) query = data_source.xpath("/TableData/Query/text()") query_collect = [] for j in query: # 數(shù)據(jù)集SQL query_collect.append(str(j).strip()) query_string = "".join(query_collect) # 將 解析結(jié)果 拼接到 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))
運行結(jié)果
{
"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}'"
}
可以看到,報表模板路徑,數(shù)據(jù)集名稱,數(shù)據(jù)鏈接名稱,SQL語句都完整獲取到了。
完整代碼
最后將獲取到的內(nèi)容轉(zhuǎn)成 pandas 的 DataFrame,然后輸出到Excel
import pathlib import pandas as pd from lxml import etree # 請先下載 正式環(huán)境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") # 解析結(jié)果 收集 result_list = [] # fineReport .cpt .frm 本身是xml文件,故可直接按行匹配字符查找是否與對象有關(guān) # 遞歸獲取 工作目錄 本路徑和子路徑所有擴展名為 .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 中 數(shù)據(jù)集內(nèi)容 tabel_data_el = xml_root.xpath("http://*/TableDataMap//TableData[@class='com.fr.data.impl.DBTableData']") for db_data in tabel_data_el: # 數(shù)據(jù)集名稱 date_source_name = db_data.get("name") # 轉(zhuǎn) string 取巧,重新定位數(shù)據(jù)集內(nèi)容 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: # 數(shù)據(jù)鏈接名字 conn_collect.append(str(j).strip()) conn_string = "".join(conn_collect) query = data_source.xpath("/TableData/Query/text()") query_collect = [] for j in query: # 數(shù)據(jù)集SQL query_collect.append(str(j).strip()) query_string = "".join(query_collect) # 將 解析結(jié)果 拼接到 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)
運行結(jié)果
到此這篇關(guān)于使用Python解析FineReport模板數(shù)據(jù)集的文章就介紹到這了,更多相關(guān)Python解析FineReport數(shù)據(jù)集內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python圖像處理庫PIL的ImageDraw模塊介紹詳解
這篇文章主要介紹了Python圖像處理庫PIL的ImageDraw模塊介紹詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧2020-02-02詳解pycharm連接遠程linux服務(wù)器的虛擬環(huán)境的方法
這篇文章主要介紹了pycharm連接遠程linux服務(wù)器的虛擬環(huán)境的詳細教程,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學(xué)習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-11-11python讀寫刪除復(fù)制文件操作方法詳細實例總結(jié)
這篇文章主要介紹了python讀寫刪除復(fù)制文件操作方法詳細實例總結(jié),需要的朋友可以參考下2021-04-04python實現(xiàn)與Oracle數(shù)據(jù)庫交互操作示例
這篇文章主要為大家介紹了python實現(xiàn)與Oracle數(shù)據(jù)庫交互操作示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家,多多進步,早日升職加薪2021-10-10Python使用pip安裝報錯:is not a supported wheel on this platform的解決
這篇文章主要介紹了Python使用pip安裝報錯:is not a supported wheel on this platform的解決方法,結(jié)合實例形式分析了在安裝版本正確的情況下pip安裝報錯的原因與相應(yīng)的解決方法,需要的朋友可以參考下2018-01-01Python 圖片文字識別的實現(xiàn)之PaddleOCR
OCR方向的工程師,之前一定聽說過PaddleOCR這個項目,其主要推薦的PP-OCR算法更是被國內(nèi)外企業(yè)開發(fā)者廣泛應(yīng)用,短短半年時間,累計Star數(shù)量已超過15k,頻頻登上Github Trending和Paperswithcode 日榜月榜第一2021-11-11