# How Template Merge with {{key}} Placeholders Works in OfficeCLI for docx, xlsx, and pptx Files

> Learn how OfficeCLI's merge command uses {{key}} placeholders for seamless template merging in docx xlsx and pptx files. Fill templates with JSON data effortlessly.

- Repository: [OfficeAI/OfficeCLI](https://github.com/iofficeai/OfficeCLI)
- Tags: how-to-guide
- Published: 2026-08-02

---

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

1. **Load the OOXML package** — Opens the document as a `ZipArchive` and parses the relevant XML parts
2. **Deserialize the JSON payload** — Converts the supplied data into a `key → value` dictionary
3. **Traverse the XML DOM** — Format-specific handlers walk the document tree
4. **Detect placeholders** — Compiled regex `{{\s*([^}]+)\s*}}` matches `{{key}}` patterns
5. **Substitute values** — Replaces text content with JSON values, preserving surrounding formatting tags
6. **Handle empty placeholders** — Injects non-breaking spaces or minimal blocks to prevent layout collapse
7. **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`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/Handlers/Word/WordHandler.Helpers.FindReplace.cs)

The [`WordHandler.Helpers.FindReplace.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/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

```bash

# CLI usage for Word template merge

officecli merge template.docx report-001.docx \
    '{"client":"Acme Corp","total":"$5,200","date":"2026-07-15"}'

```

```python

# 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`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/Handlers/Excel/ExcelHandler.cs)

The [`ExcelHandler.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/ExcelHandler.cs) processes:

- Standard cell values in `SheetData` rows
- 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.

```bash

# CLI usage for Excel template merge

officecli merge budget-template.xlsx budget-q2.xlsx data.json

```

```python

# 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`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/Handlers/Pptx/PptxBatchEmitter.Resources.cs)

The [`PptxBatchEmitter.Resources.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/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.

```bash

# CLI usage for PowerPoint template merge

officecli merge deck-template.pptx q4-acme.pptx '{"title":"Q4 Report","author":"AI Agent"}'

```

```javascript
// 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`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/Handlers/Word/WordHandler.Helpers.FindReplace.cs) | Scans Word runs, detects `{{key}}` patterns, preserves run properties |
| [`src/officecli/Handlers/Excel/ExcelHandler.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/Handlers/Excel/ExcelHandler.cs) | Walks worksheet XML, handles standard and rich-text cell replacement |
| [`src/officecli/Handlers/Pptx/PptxBatchEmitter.Resources.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/Handlers/Pptx/PptxBatchEmitter.Resources.cs) | Replaces placeholders in PowerPoint shapes, tables, and chart titles |
| [`src/officecli/Commands/MergeCommand.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/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`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.Helpers.FindReplace.cs), [`ExcelHandler.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/ExcelHandler.cs), and [`PptxBatchEmitter.Resources.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/PptxBatchEmitter.Resources.cs) implement 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.