# 技术文档:`xlsx_data_processor.py` --- ## 概述 该模块提供了一个用于处理 Excel(`.xlsx`)文件和结构化数据的工具集,支持从 `.xlsx` 文件中读取数据并将其转换为结构化的字典对象。它特别适用于管理具有特定格式规范的 CRUD(创建、读取、更新、删除)配置表,并能自动解析字段类型、主键、外键、索引等元信息。 模块主要功能包括: - 从 `.xlsx` 文件加载数据并按工作表组织。 - 支持自定义字段类型的自动转换(如 `int`, `float`, `json` 等)。 - 支持扩展的数据格式(如 `cruddata`, `xlsxdata`)通过字符串协议调用。 - 提供对特殊格式的 CRUD 配置文件的支持(包含 `summary`, `fields`, `validation` 等 sheet)。 - 命令行接口,可批量合并多个数据源(Excel 和参数)输出 JSON。 --- ## 依赖库 ```python import os import sys from traceback import print_exc from openpyxl import load_workbook from appPublic.myjson import loadf, dumpf, dumps from appPublic.dictObject import DictObject ``` > ⚠️ 注意:`appPublic` 是一个自定义公共库,需确保已安装或路径正确。 --- ## 核心类与函数说明 ### 1. `TypeConvert` 类 负责将原始值根据指定类型进行安全转换。 #### 方法列表: | 方法 | 描述 | |------|------| | `conv(typ, v)` | 根据类型名 `typ` 调用对应的转换方法(如 `to_int`),若无则返回原值。 | | `to_int(v)` | 转换为整数,失败返回 `0`。 | | `to_float(v)` | 转换为浮点数,失败返回 `0.0`。 | | `to_str(v)` | 转换为字符串,失败返回空串 `''`。 | | `to_json(v)` | 将字符串解析为 JSON 对象,空字符串保持不变,失败返回原值。⚠️ 存在 bug:应使用 `loads` 但代码中写成了 `loads(v)` 实际未导入。 | | `to_date(v)`, `to_time(v)`, `to_timestamp(v)` | 占位方法,直接返回原值(未来可扩展)。 | | `to_cruddata(v)` | 解析形如 `"cruddata:\"filename\".property"` 的字符串,动态加载 `CRUDData` 并执行属性/方法访问。 | | `to_xlsxdata(v)` | 类似 `to_cruddata`,但用于普通 `XLSXData` 对象。 | > ✅ 示例输入:`"cruddata:\"user.xlsx\".users"` → 加载 `user.xlsx` 并获取其 `users` 表数据。 > ❗ Bug 提示:`to_json` 中使用了未定义的 `loads` 函数,应改为 `from json import loads` 或使用 `dumps` 所属模块中的 `loads`。 --- ### 2. `CRUDException(Exception)` 类 自定义异常类,用于报告 `.xlsx` 文件处理过程中的错误。 #### 属性: - `xlsfile`: 出错的文件名 - `errmsg`: 错误描述 #### `__str__()` 返回格式: ``` filename:<文件名> error:<错误信息> ``` --- ### 3. `XLSXData` 类 通用 `.xlsx` 文件读取器,将每个工作表解析为记录列表,并封装成 `DictObject`。 #### 构造函数:`__init__(xlsxfile, book=None)` - `xlsxfile`: Excel 文件路径 - `book`: 可选的已打开的 `Workbook` 对象(用于性能优化或复用) #### 主要方法: | 方法 | 功能 | |------|------| | `_read()` | 内部方法,遍历所有 sheet 并调用 `readRecords()` 构建 `self.data`。 | | `get_data()` | 返回最终解析后的数据对象(`DictObject`)。 | | `readRecords(name, sheet)` | 读取单个 sheet 数据:
- 第一行作为字段定义(格式:`字段名:类型`)
- 后续行为数据行
- 使用 `TypeConvert` 进行类型转换
- 返回 `{name: [DictObject(...), ...]}` | | `getFieldNames(row)` | 处理首行字段:
- 若为空则命名为 `F_i`
- 分割 `name:type` 形式,缺失类型设为 `None`
- 返回 `[ [字段名, 类型], ... ]` | > 📌 字段命名规则示例: > - `id:int` → 名称 `id`,类型 `int` > - `username` → 名称 `username`,类型 `None` > - 空单元格 → 自动命名为 `F_0`, `F_1`... --- ### 4. `CRUDData(XLSXData)` 类 继承自 `XLSXData`,专用于处理符合 CRUD 元数据规范的 `.xlsx` 文件。 #### 规范要求: 必须包含以下三个工作表: - `summary`: 表基本信息(如主键) - `fields`: 字段定义列表 - `validation`: 验证规则(外键、索引等) #### 类方法:`isMe(book)` 判断给定 workbook 是否满足 CRUDData 格式(检查是否存在上述三个 sheet)。 #### 重写 `_read()` 方法流程: 1. 调用父类 `_read()` 解析所有 sheet。 2. 验证 `summary`, `fields`, `validation` 存在且唯一。 3. 执行元数据转换: - `convPrimary()`: 解析主键字段(逗号分隔) - `convForeignkey()`: 解析外键规则(格式:`table:value:title`) - `convIndex()`: 解析索引定义(格式:`idx_type:key1,key2`) - `check_codes_fields()`: 验证 `codes` 表中的字段是否存在于 `fields` #### 辅助方法: | 方法 | 功能 | |------|------| | `check_field(fieldname)` | 检查字段是否在 `fields` 表中存在 | | `getFieldByNmae(fields, name)` | 获取指定名称的字段定义(拼写错误:`Nmae` 应为 `Name`)❗ | | `getFKs(validation)` | 提取所有外键规则(`oper == 'fk'`) | | `getIDXs(validation)` | 提取所有索引规则(`oper == 'idx'`) | > ⚠️ Bug 提示: > - `getFieldByNmae` 函数名拼写错误,可能导致调用失败。 > - `getFKs` 中条件判断写成了 `'oepr'` 而非 `'oper'`,导致无法识别外键。 --- ### 5. `xlsxFactory(xlsxfilename)` 函数 根据文件内容自动选择合适的类实例化(工厂模式)。 #### 流程: 1. 打开 `.xlsx` 文件。 2. 遍历 `XLSXData` 的所有子类(递归查找),调用 `isMe(book)` 判断是否匹配。 3. 匹配成功则返回 `CRUDData` 实例,否则返回默认 `XLSXData` 实例。 4. 异常捕获并打印堆栈。 > ✅ 支持插件式扩展:可通过新增子类实现其他专用格式识别。 --- ### 6. `ValueConvert(s)` 函数 解析特殊前缀字符串,支持外部资源引用。 | 前缀 | 行为 | |------|------| | `xlsfile::path/to/file.xlsx` | 使用 `xlsxFactory` 加载并返回 `.get_data()` | | `jsonfile::path/to/data.json` | 使用 `loadf()` 读取 JSON 文件 | | 其他 | 直接返回原字符串 | --- ### 7. `paramentHandle(ns)` 函数 对参数字典中的每个值应用 `ValueConvert`,实现参数注入时的自动资源加载。 > ✅ 示例: ```bash python script.py data=xlsfile::config.xlsx user=jsonfile::user.json ``` → 自动加载 Excel 和 JSON 文件内容。 --- ## 主程序入口(`if __name__ == '__main__':`) 支持命令行运行,用法如下: ### 参数格式: - `key=value`:设置命名参数(支持 `xlsfile::`, `jsonfile::`) - `filepath`:直接加载数据文件(仅限 `.xlsx`, `.xls`) ### 执行流程: 1. 解析命令行参数,分离 `ns`(命名空间)和 `datafiles`(文件列表)。 2. 处理 `ns` 中的值(调用 `paramentHandle`)。 3. 遍历 `datafiles`,使用 `xlsxFactory` 加载每个 Excel 文件。 4. 合并所有数据到 `retData`。 5. 输出合并后的 JSON 结果(使用 `dumps` 格式化)。 ### 示例命令: ```bash python xlsx_data_processor.py \ config=xlsfile::app_config.xlsx \ user=jsonfile::default_user.json \ roles.xlsx \ permissions.xlsx ``` 输出结果为整合所有来源数据的 JSON 对象。 --- ## 已知问题与改进建议 | 问题 | 描述 | 建议修复 | |------|------|----------| | `to_json` 使用 `loads` 未定义 | 导致 JSON 解析失败 | 改为 `from json import loads` 或使用 `dumps.loads()` | | `getFieldByNmae` 拼写错误 | 方法名错误 | 更正为 `getFieldByName` | | `getFKs` 条件判断错误 | `'oepr' == 'fk'` 永不成立 | 改为 `'oper'` | | `check_field(f for f in ...)` | 语法错误,不能传生成器 | 改为循环逐一检查每个字段 | | `vs < 3` 在 `split` 后无效 | `vs` 是 list,比较 `< 3` 不合理 | 应改为 `len(vs) < 3` | | `to_cruddata` / `to_xlsxdata` 中 `vs[2] is None` | `split` 不会返回 `None` 元素 | 应改为 `len(vs) <= 2` 判断是否有命令部分 | --- ## 使用示例 ### 示例 Excel 结构(`users.xlsx`) **Sheet: users** ``` id:int,name:str,age:int 1,Alice,25 2,Bob,30 ``` **Sheet: summary** ``` table:primary users:id ``` **Sheet: fields** ``` name,type,desc id,int,用户ID name,str,用户名 age,int,年龄 ``` ### 调用方式: ```python d = xlsxFactory('users.xlsx') data = d.get_data() print(data.users[0].name) # 输出: Alice print(data.summary[0].primary) # 输出: ['id'] ``` --- ## 总结 本模块是一个轻量级但功能丰富的 `.xlsx` 数据处理器,适合用于配置中心、元数据管理、自动化脚本等场景。结合自定义前缀协议和工厂模式,具备良好的扩展性。 尽管存在少量 bug 和命名问题,整体设计清晰,层次分明,易于维护和二次开发。 --- > **作者**:Auto-generated Technical Documentation > **版本**:1.0 > **最后更新**:2025-04-05