{"slug": "decompiling-an-excel-template-into-a-script-4-json", "title": "Decompiling an Excel template into a script - #4 JSON", "summary": "Kookerella Ltd's open-source tool Kookerella.FsOpenXmlDsl.Mcp version 1.0.0 enables decompiling Excel templates into JSON and rebuilding them into .xlsx files, as demonstrated in a four-part series where a PowerShell script reads orders.json and generates an invoice workbook with formulas and styling. The tool, installed via `dotnet tool install -g Kookerella.FsOpenXmlDsl.Mcp`, converts templates with `fsopenxmldsl-mcp convert` and builds with `fsopenxmldsl-mcp build`, preserving data, formulas, and styles in plain JSON.", "body_md": "# Decompiling an Excel template into a script - #4 JSON\n\nThis is the JSON counterpart to [the XSLT walkthrough](/posts/decompiling-excel-template-3-xslt/),\nthe last of this four-part series, but the story is slightly different. XML pairs\nnaturally with a declarative transform language (XSLT). JSON doesn’t really have an\nequivalent standard — there’s no dotnet-tool-shaped “jq for .NET” to lean on. So instead\nof a transform engine applied to a data file, this demo is just what a JSON pipeline\nnaturally looks like in practice: **a plain script that already emits JSON**, wired\nstraight into `fsopenxmldsl-mcp build`\n\n. The full project is on GitHub:\n[Kookerella.Demo.DecompileToSource](https://github.com/Kookerella-Ltd/Kookerella.Demo.DecompileToSource).\n\n## What we’re starting from\n\nThe same plain Excel file used in the other three demos: a bold, 16pt “INVOICE” title, a\nwhite-on-navy header row with a bottom border, and two sample line-item rows with an\n`Amount`\n\ncolumn computed as `Qty * Unit Price`\n\n.\n\n## Step 1: Install the tool\n\n```\ndotnet tool install -g Kookerella.FsOpenXmlDsl.Mcp\n```\n\n## Step 2: Reverse-engineer the template\n\n```\nfsopenxmldsl-mcp convert templates/InvoiceTemplate.xlsx --lang json -o decompiled/InvoiceTemplate.json\n```\n\nThis prints out plain JSON — not source code, just the workbook’s own data and styling,\nvalidated against the tool’s own `Json.schema.json`\n\nschema. A trimmed excerpt, the\n“Widgets” row:\n\n```\n{ \"ref\": \"A4\", \"text\": \"Widgets\" },\n{ \"ref\": \"B4\", \"number\": 3 },\n{ \"ref\": \"C4\", \"number\": 9.99, \"style\": { \"numberFormat\": \"currency\" } },\n{\n  \"ref\": \"D4\",\n  \"formula\": { \"expression\": \"B4*C4\", \"cachedValue\": 29.97 },\n  \"style\": { \"numberFormat\": \"currency\" }\n}\n```\n\nText, numbers, a formula with its cached value, and styling — all as plain JSON, no code to read.\n\n## Step 3: Turning the decompiled snippet into a generation script\n\nThe decompiled JSON is disposable — it’s the starting point, not the deliverable. The\nmaintained version is split across two files: `orders.json`\n\n(the data that varies\ninvoice to invoice) and `build.ps1`\n\n(reads `orders.json`\n\n, builds the workbook JSON — the\nstyling objects copied verbatim from the decompiled file, as PowerShell `[ordered]`\n\nhashtables — and writes it out).\n\nThe diff from the decompiled file is deliberately small — the title cell and the four header cells are the exact same shape as the decompiled JSON, just written as PowerShell hashtables instead of raw JSON. Only the two hardcoded “Widgets”/“Gadgets” objects became this loop:\n\n``` php\nfor ($i = 0; $i -lt $orders.Count; $i++) {\n    $order = $orders[$i]\n    $row = 4 + $i\n    $amount = [double]$order.quantity * [double]$order.unitPrice\n\n    $cells += [ordered]@{ ref = \"A$row\"; text = $order.item }\n    $cells += [ordered]@{ ref = \"B$row\"; number = $order.quantity }\n    $cells += [ordered]@{ ref = \"C$row\"; number = $order.unitPrice; style = $currencyStyle }\n    $cells += [ordered]@{\n        ref     = \"D$row\"\n        formula = [ordered]@{ expression = \"B$row*C$row\"; cachedValue = $amount }\n        style   = $currencyStyle\n    }\n}\n```\n\nThis is the plain-script mirror of the C# demo’s collection-expression spread, the F#\ndemo’s `yield!`\n\n, and the XSLT demo’s `xsl:for-each`\n\n— same idea (build one row per\norder), a fourth different way to express it, this time with no special language feature\nat all, just an array and a loop.\n\n`[ordered]@{...}`\n\n(rather than plain `@{...}`\n\n) matters here: PowerShell’s built-in\nhashtable doesn’t preserve key order, and an unordered one would still work\n(`fsopenxmldsl-mcp build`\n\ndoesn’t care about JSON key order) but would make the generated\nfile harder to read and diff against the decompiled reference.\n\n## Step 4: Building the Excel file\n\n```\n.\\build.ps1\n```\n\nInternally, this serializes the hashtables above with `ConvertTo-Json -Depth 10`\n\n, writes\nthe result to `invoice.workbook.json`\n\n, and then runs:\n\n```\nfsopenxmldsl-mcp build invoice.workbook.json invoice.xlsx\n```\n\n`build`\n\nis the inverse of `convert --lang json`\n\n: it reads JSON matching the tool’s\n`Json.schema.json`\n\nschema and writes a real `.xlsx`\n\n. **No C#, F#, or XSLT was involved\nanywhere in this pipeline.** The only “code” is a short, ordinary script — which is also\nthe point: most real JSON pipelines (a report generator, an API response, a CI job) are\nalready exactly this shape.\n\n## Step 5: Prove it stays correct\n\nThis pipeline is tested the same way the other three demos are — by running the actual\n`build.ps1`\n\nscript and inspecting the result, rather than trusting that the script\n“looks right”:\n\n**Schema validity**— runs a real`OpenXmlValidator`\n\nover the output.**Correctness**— feeds in 0, 1, and 3 orders and checks the row count and the`Amount`\n\nformula for each one.**Styling preservation**— pins the exact colors, bold, font size, and border style that came from the original template.\n\n## Recap\n\n| Step | Command | Output |\n|---|---|---|\n| Install the tool | `dotnet tool install -g Kookerella.FsOpenXmlDsl.Mcp` | `fsopenxmldsl-mcp` on your PATH |\n| Reverse-engineer | `fsopenxmldsl-mcp convert InvoiceTemplate.xlsx --lang json -o InvoiceTemplate.json` | Plain JSON that reproduces the original `.xlsx` exactly |\n| Make it data-driven | Replace hardcoded JSON objects with a loop over your own data | `build.ps1` |\n| Build | `fsopenxmldsl-mcp build invoice.workbook.json invoice.xlsx` | A real, schema-valid `.xlsx` |\n| Verify | `dotnet test` | Schema validity, formula correctness, and styling all pinned by real tests |\n\nFour languages, one template, one idea: decompile it once, then keep only the two lines\nthat actually change. See the [FsOpenXmlDsl](/products/fsopenxmldsl/) and\n[MCP server](/products/fsopenxmldsl-mcp/) product pages for the libraries behind all four.", "url": "https://wpnews.pro/news/decompiling-an-excel-template-into-a-script-4-json", "canonical_source": "https://kookerella.com/posts/decompiling-excel-template-4-json/", "published_at": "2026-08-29 00:00:00+00:00", "updated_at": "2026-08-30 13:52:41.466007+00:00", "lang": "en", "topics": ["developer-tools"], "entities": ["Kookerella Ltd", "Kookerella.FsOpenXmlDsl.Mcp", "PowerShell", "JSON", "Excel"], "alternates": {"html": "https://wpnews.pro/news/decompiling-an-excel-template-into-a-script-4-json", "markdown": "https://wpnews.pro/news/decompiling-an-excel-template-into-a-script-4-json.md", "text": "https://wpnews.pro/news/decompiling-an-excel-template-into-a-script-4-json.txt", "jsonld": "https://wpnews.pro/news/decompiling-an-excel-template-into-a-script-4-json.jsonld"}}