You don’t have to hand-write Excel styling code. If someone already built the spreadsheet you need to reproduce — a finance person’s invoice template, a report layout a designer signed off on — you can reverse-engineer it into real source code, then wire in your own data. This is the first of four posts walking through the same demo in C#, F#, XSLT, and plain JSON. The full project is on GitHub: Kookerella.Demo.DecompileToSource.

What we’re starting from

A plain Excel file, built by hand in Excel. It has:

  • A bold, 16pt “INVOICE” title
  • A header row styled white-on-navy with a bottom border
  • Two sample line-item rows, with an Amount column computed as Qty * Unit Price

Nobody wrote any code to produce this file — it’s just a spreadsheet.

Step 1: Install the tool

The reverse-engineering happens via a CLI tool, fsopenxmldsl-mcp, published as a dotnet global tool:

dotnet tool install -g Kookerella.FsOpenXmlDsl.Mcp

Step 2: Reverse-engineer the template

fsopenxmldsl-mcp convert templates/InvoiceTemplate.xlsx --lang csharp -o decompiled/InvoiceTemplate.g.cs

This reads the real .xlsx file and prints out C# code that reproduces it exactly. The top line of the result is:

#:package Kookerella.CsOpenXmlDsl@0.3.2

That #:package line is a .NET 10 file-based app directive — this single .cs file is a complete, runnable program with no .csproj needed. You can run it immediately, on any machine with the .NET 10 SDK:

cd decompiled
dotnet run InvoiceTemplate.g.cs

That produces output.xlsx — pixel-for-pixel the same as the original template. Nothing was lost in translation: title, header styling, borders, currency formatting, and the Qty * Unit Price formulas are all there, expressed as plain C# method calls (Cell.Text(...), .WithStyle(...), Cell.Formula(...), and so on).

This is the point where “decompiling a spreadsheet” stops being a metaphor. You now have the template as source code you can read, diff, and edit.

Step 3: Adding the package to a real project

The file-based app above pinned the package inline for convenience. In a normal project you add it the usual way:

dotnet add package Kookerella.CsOpenXmlDsl

Kookerella.CsOpenXmlDsl is a C# wrapper around a separate F# core library, Kookerella.FsOpenXmlDsl, which does the actual OOXML reading/writing.

Step 4: Turning the decompiled snippet into real code

The decompiled file is disposable — it’s the starting point, not the deliverable. Nobody wants to hardcode “Widgets” and “Gadgets” forever. The diff from the decompiled file to a maintained version is deliberately small:

  1. Wrap the top-level statements in a class and a Build method that takes real data (IEnumerable<OrderLine>) instead of running standalone.

  2. Replace the two hardcoded item rows with a LINQ projection over that data:

    var dataRows = orders.Select((order, i) =>
    {
        var row = 4 + i;
        return Row.Of(
            Cell.Text(order.Item),
            Cell.Number(order.Quantity),
            Cell.Number(order.UnitPrice).WithStyle(CellStyle.Default.WithNumberFormat(NumberFormatKind.Currency)),
            Cell.Formula($"B{row}*C{row}", order.Quantity * order.UnitPrice).WithStyle(CellStyle.Default.WithNumberFormat(NumberFormatKind.Currency)));
    });
    
  3. Splice the generated rows into the sheet with a C# collection expression, instead of listing two hardcoded rows:

    var sheet0 = Sheet.Create(
        "Invoice",
        [
            /* title row, exactly as decompiled */,
            /* header row, exactly as decompiled */,
            .. dataRows,
        ]);
    

Everything else — every style call, every color, every border — is copied verbatim from the decompiled file. The styling was never hand-written by a developer in the first place, so there’s nothing to “port” — only the two data rows needed to become data-driven.

Step 5: Prove it stays correct

Because this is now real code, it can be tested like real code — something you can’t do to a .xlsx file sitting on a file share. The test suite checks three things a spreadsheet can’t check about itself:

  • Schema validity — runs a real OpenXmlValidator over the output. If a future change ever produces invalid OOXML, this catches it immediately instead of someone discovering a “repair this file?” dialog in Excel weeks later.
  • Correctness — feeds in 0, 1, and 3 orders and checks the row count and the Amount formula text/value are correct for each one.
  • Styling preservation — pins the exact colors, bold, font size, and border style that came from the original template, so a future edit can’t silently drift the invoice’s look away from what the original designer signed off on.

Recap

StepCommandOutput
Install the tooldotnet tool install -g Kookerella.FsOpenXmlDsl.Mcpfsopenxmldsl-mcp on your PATH
Reverse-engineerfsopenxmldsl-mcp convert InvoiceTemplate.xlsx --lang csharp -o InvoiceTemplate.g.csA runnable C# file that reproduces the original .xlsx exactly
Add the packagedotnet add package Kookerella.CsOpenXmlDslThe C# wrapper over the F# core
Make it data-drivenReplace hardcoded rows with a LINQ projection over your own data modelA maintained generator
Verifydotnet testSchema validity, formula correctness, and styling all pinned by real tests

The template never had to be redesigned in code, and the developer never had to reverse-engineer OOXML XML by hand — the tool did that translation, once, and everything after that is ordinary, testable C#. Next up: the same demo in F#.