Files
claudeskill/skills/excel-report-converter/SKILL.md
Misaka Company bdd2df7e75 Optimize excel-report-converter verification for large files
Add guidance to verify only first 10 records when validating large export files, avoiding processing time and memory issues. Also add temp/ to .gitignore.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-27 17:48:38 +08:00

9.2 KiB

name, description
name description
excel-report-converter 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:

# 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:

#!/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:

python3 scripts/custom_converter.py input.xlsx output.xlsx

Use excel-to-markdown to verify the output:

# For large files, only verify first 10 records
python3 scripts/excel_to_markdown.py output.xlsx -o /tmp/verify.md --show-rows --show-cols --rows 1:11

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

Important: For large output files with many records, use --rows 1:11 to only convert and verify the first 10 data records (plus header row). This avoids processing time and memory issues when verifying large exports.

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:

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:

# 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.