xls2ddl/aidocs/xlsxData.md
2025-10-12 13:57:44 +08:00

258 lines
8.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 技术文档:`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 数据:<br> - 第一行作为字段定义(格式:`字段名:类型`<br> - 后续行为数据行<br> - 使用 `TypeConvert` 进行类型转换<br> - 返回 `{name: [DictObject(...), ...]}` |
| `getFieldNames(row)` | 处理首行字段:<br> - 若为空则命名为 `F_i`<br> - 分割 `name:type` 形式,缺失类型设为 `None`<br> - 返回 `[ [字段名, 类型], ... ]` |
> 📌 字段命名规则示例:
> - `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