Add excel-report-converter skill and documentation
- Add excel-report-converter skill for generating Python scripts to convert report-style Excel files to database-record format - Skill analyzes report structure (header + detail rows + footer) and generates custom conversion scripts - Update README.md to document the new skill and report_to_db_format.py script - The skill integrates with excel-to-markdown for structure analysis and validation Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
29
README.md
29
README.md
@@ -12,13 +12,14 @@
|
||||
claudeskill/
|
||||
├── .claude/ # Claude 配置目录
|
||||
│ └── skills/ # Skill 创建器引用
|
||||
│ └── skill-creator/ # Skill 创建指南和工具
|
||||
│ ├── skill-creator/ # Skill 创建指南和工具
|
||||
│ ├── excel-to-markdown/ # Excel 转 Markdown Skill
|
||||
│ └── excel-report-converter/ # Excel 报表转换 Skill
|
||||
├── scripts/ # 独立脚本目录
|
||||
│ └── excel_to_markdown.py # Excel 转 Markdown 转换器
|
||||
├── skills/ # 创建的 Skills
|
||||
│ └── excel-to-markdown/ # Excel 转 Markdown Skill
|
||||
│ ├── SKILL.md # Skill 文档
|
||||
│ └── scripts/ # Skill 附带脚本
|
||||
│ ├── excel_to_markdown.py # Excel 转 Markdown 转换器
|
||||
│ └── report_to_db_format.py # 报表格式转数据库格式脚本
|
||||
├── skills/ # 开发中的 Skills
|
||||
│ └── excel-report-converter/ # Excel 报表转换器
|
||||
├── .venv/ # Python 虚拟环境
|
||||
└── README.md # 本文档
|
||||
```
|
||||
@@ -30,6 +31,7 @@ claudeskill/
|
||||
|
||||
**当前脚本:**
|
||||
- `excel_to_markdown.py` - 将 Excel 文件转换为 Markdown 表格格式
|
||||
- `report_to_db_format.py` - 将报表格式的 Excel 文件转换为数据库记录格式
|
||||
|
||||
### `skills/`
|
||||
存放已创建的 Skills,每个 Skill 都是一个独立的功能模块。
|
||||
@@ -52,6 +54,21 @@ claudeskill/
|
||||
- 生成带行/列编号的 Markdown 表格
|
||||
- 处理大型电子表格的部分转换
|
||||
|
||||
#### excel-report-converter
|
||||
生成 Python 脚本将报表格式的 Excel 文件转换为数据库记录格式的 Skill。
|
||||
|
||||
**功能:**
|
||||
- 自动分析 Excel 报表结构(表头、明细、表尾)
|
||||
- 识别多个垂直排列的相同格式报表
|
||||
- 生成专用的转换脚本
|
||||
- 将层级报表数据转换为扁平的数据库记录
|
||||
|
||||
**使用场景:**
|
||||
- 将包含多个报表的 Excel 文件转换为数据库表格式
|
||||
- 分析报表格式的 Excel 文档结构
|
||||
- 创建自定义的 Excel 报表转换脚本
|
||||
- 将层级报表数据(表头 + 明细行 + 表尾)转换为规范化数据库记录
|
||||
|
||||
## 工作流程
|
||||
|
||||
### 1. 创建新 Skill
|
||||
|
||||
259
skills/excel-report-converter/SKILL.md
Normal file
259
skills/excel-report-converter/SKILL.md
Normal file
@@ -0,0 +1,259 @@
|
||||
---
|
||||
name: excel-report-converter
|
||||
description: Generate Python scripts to convert report-style Excel files to database-record format. Use for converting Excel files with multiple stacked reports into flat database tables, analyzing report structure, creating custom conversion scripts for specific Excel report formats, and transforming hierarchical report data (header + detail lines + footer) into normalized database records
|
||||
---
|
||||
|
||||
# Excel Report Converter
|
||||
|
||||
Generate Python scripts to convert report-style Excel files (multiple reports per worksheet) into database-record format (flat table).
|
||||
|
||||
## When to Use
|
||||
|
||||
Use this skill when:
|
||||
- User provides an Excel file with multiple similar reports stacked vertically in one worksheet
|
||||
- Each report has hierarchical structure: header information + detail data rows + footer information
|
||||
- User wants to convert to database-record format where header fields are repeated for each detail row
|
||||
- The report structure is consistent across all reports in the file
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Extract and Analyze Report Structure
|
||||
|
||||
Use the `excel-to-markdown` skill to convert the Excel file to markdown format for analysis:
|
||||
|
||||
```bash
|
||||
# Convert Excel to markdown to analyze structure
|
||||
python3 scripts/excel_to_markdown.py input.xlsx -o /tmp/analysis.md --show-rows --show-cols
|
||||
```
|
||||
|
||||
Read the markdown file and identify:
|
||||
1. **Report delimiters**: How to identify where each report starts/ends (e.g., specific title in column 1)
|
||||
2. **Header structure**: Which rows contain header information and what fields are in each column
|
||||
3. **Detail table**: Which row contains column headers and where detail data starts/ends
|
||||
4. **Footer structure**: Which rows contain footer information and where the data is located
|
||||
5. **Row separators**: Are there empty rows between reports? After the last row?
|
||||
|
||||
### Step 2: Generate Conversion Script
|
||||
|
||||
Create a Python script with the following structure:
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Convert report-style Excel files to database-record format
|
||||
Customized for: [describe the report format]
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from openpyxl import load_workbook
|
||||
from openpyxl.utils import get_column_letter
|
||||
|
||||
class ReportParser:
|
||||
def __init__(self, worksheet):
|
||||
self.ws = worksheet
|
||||
self.max_row = worksheet.max_row
|
||||
self.max_col = worksheet.max_column
|
||||
|
||||
def find_report_blocks(self):
|
||||
"""Identify start and end rows for each report block"""
|
||||
# Implement block detection logic
|
||||
# Look for report delimiters (e.g., title in column 1)
|
||||
# Exclude trailing empty rows
|
||||
pass
|
||||
|
||||
def parse_header(self, start_row):
|
||||
"""Extract header fields from the report header section"""
|
||||
# Map cell positions to field names
|
||||
pass
|
||||
|
||||
def parse_detail_rows(self, start_row, end_row):
|
||||
"""Extract detail rows from the report detail section"""
|
||||
# Identify column header row
|
||||
# Extract data until empty row or footer starts
|
||||
pass
|
||||
|
||||
def parse_footer(self, end_row):
|
||||
"""Extract footer fields from the report footer section"""
|
||||
# Map cell positions to field names
|
||||
pass
|
||||
|
||||
def parse_report(self, start_row, end_row):
|
||||
"""Parse complete report: header + details + footer"""
|
||||
header = self.parse_header(start_row)
|
||||
details = self.parse_detail_rows(start_row, end_row)
|
||||
footer = self.parse_footer(end_row)
|
||||
return header, details, footer
|
||||
|
||||
def convert_to_database_format(input_file, output_file, sheet_name=None):
|
||||
"""Convert report format to database-record format"""
|
||||
wb = load_workbook(input_file, data_only=True)
|
||||
ws = wb[sheet_name] if sheet_name else wb.active
|
||||
|
||||
parser = ReportParser(ws)
|
||||
blocks = parser.find_report_blocks()
|
||||
|
||||
# Collect all records
|
||||
all_records = []
|
||||
for start_row, end_row in blocks:
|
||||
header, details, footer = parser.parse_report(start_row, end_row)
|
||||
# Merge header + each detail row + footer
|
||||
for detail in details:
|
||||
record = {**header, **detail, **footer}
|
||||
all_records.append(record)
|
||||
|
||||
# Write output
|
||||
from openpyxl import Workbook
|
||||
wb_out = Workbook()
|
||||
ws_out = wb_out.active
|
||||
|
||||
# Write header row
|
||||
fields = list(all_records[0].keys())
|
||||
for col_idx, field_name in enumerate(fields, start=1):
|
||||
ws_out.cell(row=1, column=col_idx, value=field_name)
|
||||
|
||||
# Write data rows
|
||||
for row_idx, record in enumerate(all_records, start=2):
|
||||
for col_idx, field_name in enumerate(fields, start=1):
|
||||
ws_out.cell(row=row_idx, column=col_idx, value=record.get(field_name))
|
||||
|
||||
wb_out.save(output_file)
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Convert report-style Excel to database-record format')
|
||||
parser.add_argument('input_file', help='Input Excel file')
|
||||
parser.add_argument('output_file', help='Output Excel file')
|
||||
parser.add_argument('--sheet', help='Worksheet name (default: active)')
|
||||
args = parser.parse_args()
|
||||
|
||||
convert_to_database_format(args.input_file, args.output_file, args.sheet)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
```
|
||||
|
||||
**Key Implementation Points:**
|
||||
|
||||
- **Column mapping**: Use fixed column indices (1-indexed) or use openpyxl's column letters
|
||||
- **Empty row detection**: Check if all cells in a row are None/empty to identify boundaries
|
||||
- **Date handling**: Excel dates may be numeric - use appropriate conversion if needed
|
||||
- **Merged cells**: Check for merged cells in header/footer sections
|
||||
- **Data types**: Preserve original data types (strings, numbers, dates) from source
|
||||
|
||||
### Step 3: Test and Verify
|
||||
|
||||
Run the generated script to convert the file:
|
||||
|
||||
```bash
|
||||
python3 scripts/custom_converter.py input.xlsx output.xlsx
|
||||
```
|
||||
|
||||
Use `excel-to-markdown` to verify the output:
|
||||
|
||||
```bash
|
||||
python3 scripts/excel_to_markdown.py output.xlsx -o /tmp/verify.md --show-rows --show-cols
|
||||
```
|
||||
|
||||
Read `/tmp/verify.md` and verify:
|
||||
1. All records are extracted (count should match total detail rows across all reports)
|
||||
2. Header fields are correctly populated for each record
|
||||
3. Detail fields are correctly mapped
|
||||
4. Footer fields are correctly populated
|
||||
5. No data loss or corruption
|
||||
|
||||
### Step 4: Iterate if Needed
|
||||
|
||||
If verification reveals issues:
|
||||
1. Identify the specific problem (wrong column index, missing field, incorrect row detection)
|
||||
2. Fix the script accordingly
|
||||
3. Re-run the conversion
|
||||
4. Re-verify with excel-to-markdown
|
||||
5. Repeat until output is correct
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Report Block Detection
|
||||
|
||||
Most report-style Excel files use one of these patterns:
|
||||
|
||||
**Pattern A: Title-based delimiters**
|
||||
```
|
||||
Row 1: Report Title
|
||||
Row 2: [header data]
|
||||
...
|
||||
Row N: [footer data]
|
||||
Row N+1: [empty or next report title]
|
||||
```
|
||||
|
||||
Look for a specific value in column 1 (e.g., "离散备料计划", "Purchase Order")
|
||||
|
||||
**Pattern B: Fixed-size reports**
|
||||
All reports have the same number of rows. Calculate block size and divide evenly.
|
||||
|
||||
### Header/Detail/Footer Separation
|
||||
|
||||
**Typical structure:**
|
||||
- Rows 1-4: Header information (labels and values in specific columns)
|
||||
- Row 5: Empty separator
|
||||
- Row 6: Detail table column headers
|
||||
- Rows 7+: Detail data rows
|
||||
- Row N-1: Footer row 1 (creator, date, approver)
|
||||
- Row N: Footer row 2 (printer, print date)
|
||||
- Row N+1: Empty separator or next report
|
||||
|
||||
### Column Mapping Strategies
|
||||
|
||||
**Strategy 1: Fixed column positions**
|
||||
Use when report format is consistent:
|
||||
```python
|
||||
factory = ws.cell(row=2, column=3).value # C列
|
||||
order_no = ws.cell(row=2, column=9).value # I列
|
||||
```
|
||||
|
||||
**Strategy 2: Search by label**
|
||||
Use when column positions may vary:
|
||||
```python
|
||||
# Find column by searching for label in first row
|
||||
for col in range(1, max_col + 1):
|
||||
if ws.cell(row=header_row, column=col).value == "Order No":
|
||||
order_no_col = col
|
||||
break
|
||||
```
|
||||
|
||||
### Field Merging Strategy
|
||||
|
||||
When creating database records:
|
||||
1. Parse header fields once per report
|
||||
2. Parse footer fields once per report
|
||||
3. For each detail row, create a merged record: `{**header, **detail_row, **footer}`
|
||||
4. This repeats header/footer fields for each detail line (database normalization)
|
||||
|
||||
## Example Report Structure Analysis
|
||||
|
||||
When analyzing the markdown output, look for:
|
||||
|
||||
```
|
||||
Row 1: | Report Title | | | ...
|
||||
Row 2: | Field: | | Value | | Field: | | Value | ...
|
||||
Row 3: | Field: | | Value | | Field: | | Value | ...
|
||||
Row 4: | (empty or separator)
|
||||
Row 5: | Col1 | Col2 | Col3 | ... (detail table headers)
|
||||
Row 6: | val1 | val2 | val3 | ... (first detail row)
|
||||
Row 7: | val1 | val2 | val3 | ... (second detail row)
|
||||
...
|
||||
Row N: | Creator: | | Name | | Date: | | 2025-01-01 |
|
||||
Row N+1: | Printer: | | Name | | Print Date: | | 2025-01-02 |
|
||||
Row N+2: | (empty) or next report title
|
||||
```
|
||||
|
||||
Map this structure to the script functions:
|
||||
- `parse_header(start_row)`: Extract fields from rows 2-3
|
||||
- `parse_detail_rows(start_row, end_row)`: Extract rows 6+ until empty/footer
|
||||
- `parse_footer(end_row)`: Extract fields from rows N to N+1
|
||||
|
||||
## Resources
|
||||
|
||||
The `excel-to-markdown` skill provides Excel-to-markdown conversion for structure analysis.
|
||||
|
||||
This skill does not include bundled scripts or references - each conversion script is generated dynamically based on the specific report format being analyzed.
|
||||
Reference in New Issue
Block a user