How Template Merge with {{key}} Placeholders Works in OfficeCLI for docx, xlsx, and pptx Files
OfficeCLI's merge command uses a universal Mustache-style {{key}} replacement engine that operates directly on OOXML structures to fill Word, Excel, and PowerPoint templates with JSON data.
The OfficeCLI tool provides a deterministic, token-free approach to document generation. By scanning the raw OOXML of .docx, .xlsx, and .pptx files, it detects {{key}} placeholders and substitutes them with JSON values while preserving all original formatting. This single syntax works identically across all three Microsoft Office formats.
How the Template Merge Engine Works
The merge process follows a consistent seven-step pipeline regardless of target format:
- Load the OOXML package — Opens the document as a
ZipArchiveand parses the relevant XML parts - Deserialize the JSON payload — Converts the supplied data into a
key → valuedictionary - Traverse the XML DOM — Format-specific handlers walk the document tree
- Detect placeholders — Compiled regex
{{\s*([^}]+)\s*}}matches{{key}}patterns - Substitute values — Replaces text content with JSON values, preserving surrounding formatting tags
- Handle empty placeholders — Injects non-breaking spaces or minimal blocks to prevent layout collapse
- Persist the modified package — Writes updated XML back to the zip archive
Because the engine operates on raw OOXML rather than rendered documents, it achieves format-agnostic performance with identical {{key}} syntax across Word, Excel, and PowerPoint.
Word Document (docx) Template Merge
In Word documents, the template merge engine targets text runs, content controls, and structured document tags.
Implementation location: src/officecli/Handlers/Word/WordHandler.Helpers.FindReplace.cs
The WordHandler.Helpers.FindReplace.cs file implements the core logic:
- Scans
<w:t>runs inside paragraphs, tables, and headers/footers - Detects content-control placeholders (
<w:sdt>elements) - Preserves run properties (
<w:rPr>) such as font, color, and style after replacement
# CLI usage for Word template merge
officecli merge template.docx report-001.docx \
'{"client":"Acme Corp","total":"$5,200","date":"2026-07-15"}'
# Python SDK
from officecli import Doc
data = {"client": "Acme Corp", "total": "$5,200"}
with Doc("invoice-template.docx") as d:
d.merge("invoice-001.docx", data)
Excel Spreadsheet (xlsx) Template Merge
Excel template merge operates on cell values, including rich-text formatting and chart metadata.
Implementation location: src/officecli/Handlers/Excel/ExcelHandler.cs
The ExcelHandler.cs processes:
- Standard cell values in
SheetDatarows - Rich-text cells by rebuilding
<is>inline string fragments - Table headers/footers and chart titles/axis labels
For rich-text cells, the engine reconstructs the entire <is> element to ensure styling (bold, color, font) remains intact after placeholder substitution.
# CLI usage for Excel template merge
officecli merge budget-template.xlsx budget-q2.xlsx data.json
# Python SDK
with Doc("budget-template.xlsx") as d:
d.merge("budget-q2.xlsx", data)
PowerPoint Presentation (pptx) Template Merge
PowerPoint template merge handles shape text, slide masters, and visual layout preservation.
Implementation location: src/officecli/Handlers/Pptx/PptxBatchEmitter.Resources.cs
The PptxBatchEmitter.Resources.cs manages:
- Shape text boxes and auto-shape placeholders (
<a:t>elements) - Table cells and chart titles
- Slide-master placeholders for consistent branding
When a placeholder is the only content of a shape, the emitter creates a "sized placeholder" using <a:solidFill> to prevent layout collapse after replacement.
# CLI usage for PowerPoint template merge
officecli merge deck-template.pptx q4-acme.pptx '{"title":"Q4 Report","author":"AI Agent"}'
// Node.js SDK
import { Doc } from "@officecli/sdk";
const data = { title: "Q4 Report", author: "AI Agent" };
await using d = await Doc.open("deck-template.pptx");
await d.merge("deck-q4.pptx", data);
Key Source Files and Their Roles
| File | Function |
|---|---|
src/officecli/Handlers/Word/WordHandler.Helpers.FindReplace.cs |
Scans Word runs, detects {{key}} patterns, preserves run properties |
src/officecli/Handlers/Excel/ExcelHandler.cs |
Walks worksheet XML, handles standard and rich-text cell replacement |
src/officecli/Handlers/Pptx/PptxBatchEmitter.Resources.cs |
Replaces placeholders in PowerPoint shapes, tables, and chart titles |
src/officecli/Commands/MergeCommand.cs |
Parses CLI arguments and dispatches to format-specific handlers |
Supported Placeholder Locations by Format
| Format | Placeholder Locations |
|---|---|
| Word (docx) | Paragraph text, tables, headers/footers, content controls (<w:sdt>), page numbers, dates |
| Excel (xlsx) | Cell values, rich-text cells, table headers/footers, chart titles, axis labels |
| PowerPoint (pptx) | Shape text boxes, table cells, chart titles, data labels, slide-master placeholders |
Summary
- Single syntax:
{{key}}placeholders work identically across Word, Excel, and PowerPoint - OOXML-native: Direct XML manipulation preserves all original formatting and styling
- Format-specific handlers:
WordHandler.Helpers.FindReplace.cs,ExcelHandler.cs, andPptxBatchEmitter.Resources.csimplement the core logic - Layout protection: Empty placeholder handling prevents document collapse
- Multi-platform: CLI, Python SDK, and Node.js SDK all support template merge operations
Frequently Asked Questions
What happens if a {{key}} in my template has no matching value in the JSON payload?
The placeholder text remains unchanged in the output document. The engine only substitutes when it finds an exact key match in the JSON dictionary, leaving unmatched {{key}} patterns untouched for manual review.
Does OfficeCLI preserve formatting like fonts, colors, and styles after replacement?
Yes. The engine specifically preserves surrounding XML formatting tags—<w:rPr> for Word, <a:pPr> for PowerPoint, and reconstructed <is> fragments for Excel—so the replaced text inherits all visual styling from the original template.
Can I use nested objects or arrays in my JSON payload for complex template data?
The current implementation uses a flat key → value dictionary. For nested data, flatten your JSON using dot notation (e.g., {"client.name": "Acme", "client.id": "12345"}) and reference keys directly as {{client.name}} in your templates.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →