How the OfficeCLI Template Merge Command Replaces {{key}} Placeholders in DOCX, XLSX, and PPTX Files
The OfficeCLI merge command uses a compiled regex pattern and single-pass substitution engine in Core/TemplateMerger.cs to replace {{key}} placeholders with flattened JSON values across Word, Excel, and PowerPoint files while preserving document formatting and reporting unresolved tokens.
The OfficeCLI template merge command provides a programmatic way to populate Microsoft Office documents using JSON data sources. Implemented in the iOfficeAI/OfficeCLI repository, the tool parses structured data, detects placeholder tokens using flexible pattern matching, and executes format-specific replacements across DOCX, XLSX, and PPTX files without altering underlying document styles.
Command Flow and Architecture
In CommandBuilder.Import.cs (lines 284‑313), the CLI defines the merge command and delegates document processing to Core/TemplateMerger.cs. The entry point first parses the JSON data argument, then invokes the merge engine:
var data = Core.TemplateMerger.ParseMergeData(dataArg);
var mergeResult = Core.TemplateMerger.Merge(template, output, data, force);
This two-phase approach separates argument handling from file manipulation, allowing the TemplateMerger class to focus exclusively on document traversal and text substitution.
JSON Data Processing and Flattening
Before reaching the document layers, TemplateMerger.ParseMergeData (lines 39‑89) normalizes input into a flat Dictionary<string,string>. The method accepts either inline JSON strings or file paths, then executes a two-pass flattening algorithm:
- Pass 1 stores literal top-level keys directly, ensuring explicit dot-notation keys like
"a.b"take precedence over nested objects. - Pass 2 flattens nested objects into dot-notation paths (
parent.child) and arrays into bracket indices (items[0]).
This flattening strategy enables templates to reference nested JSON values using intuitive {{parent.child}} or {{items[0]}} syntax.
Placeholder Detection Regex
The engine identifies placeholders using a compiled regular expression defined at line 28 of TemplateMerger.cs:
private static readonly Regex PlaceholderPattern =
new(@"\{\{\s*(\w[\w.\-\[\] ]*?)\s*\}\}", RegexOptions.Compiled);
This pattern tolerates outer whitespace, hyphens, inner spaces, dot-path navigation, and array indexes, matching tokens like {{ name }}, {{user.email}}, or {{items[0].title}}.
Format-Specific Merge Implementation
TemplateMerger.Merge copies the template to the output path, then dispatches to format-specific handlers based on file extension. Each handler preserves the host application's formatting while executing replacements.
DOCX Handling (Word Documents)
The MergeDocx method processes WordprocessingDocument parts, enumerating the main document body, headers, footers, footnotes, endnotes, and comments. For every <w:t> text element containing {{, it calls SinglePassReplace (lines 130‑166):
- Runs the regex once per text element to prevent nested placeholder expansion.
- Substitutes matching keys with dictionary values.
- Records used keys and replacement counts without feeding results back into the regex.
After replacement, ScanUnresolvedDocx (lines 168‑210) performs a second pass to collect any remaining placeholders for the final report.
XLSX Handling (Excel Workbooks)
For Excel files, MergeXlsx opens the SpreadsheetDocument and iterates through every worksheet cell. The implementation:
- Extracts cell text handling inline strings, shared strings, and plain strings.
- Calls
SinglePassReplaceon the extracted value. - Writes the result back using
SetCellTextas an inline string to preserve formatting.
A final scan identifies unresolved placeholders across all cells.
PPTX Handling (PowerPoint Presentations)
The MergePptx method processes PresentationDocument slides and notes. For each <p:sp> shape containing a TextBody:
- Concatenates all run texts from the shape.
- Executes
SinglePassReplaceon the combined string. - Re-writes the run collection: the first run receives the new text while subsequent runs are removed, preserving the original formatting of the first run.
This approach avoids breaking PowerPoint's run-based styling while ensuring placeholder text receives complete replacement.
Merge Results and Reporting
Each merge operation returns a MergeResult object containing:
- ReplacedCount: Total successful substitutions across the document.
- UsedKeys: Dictionary keys that actually appeared in the template.
- UnresolvedPlaceholders: Sorted list of placeholders that remained after substitution.
The CLI prints a summary to stdout and writes warnings to stderr when unresolved placeholders exist, enabling automated validation of template completeness.
Practical Usage Examples
Perform a basic merge using inline JSON:
officecli merge template.docx merged.docx --data '{"name":"Alice","date":"2026-07-29"}'
Use a JSON file with the force flag to overwrite existing outputs:
officecli merge report.xlsx report-out.xlsx --data data.json --force
Programmatically invoke the merger from C#:
var data = OfficeCli.Core.TemplateMerger.ParseMergeData("{\"title\":\"Q1 Report\",\"year\":2024}");
var result = OfficeCli.Core.TemplateMerger.Merge("report.pptx", "report-merged.pptx", data, force: true);
Console.WriteLine($"Replacements: {result.ReplacedCount}");
if (result.UnresolvedPlaceholders.Any())
Console.WriteLine("Unresolved: " + string.Join(", ", result.UnresolvedPlaceholders));
Summary
- The OfficeCLI
mergecommand implements a single-pass regex substitution engine inCore/TemplateMerger.csthat processes DOCX, XLSX, and PPTX files uniformly. - JSON data flattening supports dot-notation and bracket-index syntax for accessing nested values and array elements.
- Format-specific handlers preserve document structure: Word text elements, Excel cell strings, and PowerPoint shape runs retain their original styling after replacement.
- The system reports replacement metrics and unresolved placeholders, enabling template validation and debugging.
- All operations occur through the Open XML SDK, ensuring compatibility with Microsoft Office formats without requiring the Office applications to be installed.
Frequently Asked Questions
How does OfficeCLI handle nested JSON objects in templates?
OfficeCLI flattens nested JSON objects into dot-notation keys during the parsing phase in ParseMergeData. For example, a JSON object {"user": {"name": "Alice"}} becomes accessible via {{user.name}}. Arrays are flattened using bracket notation (items[0]), allowing templates to reference specific indices.
What happens if a placeholder in the template doesn't exist in the JSON data?
Unresolved placeholders remain in the document text unchanged. After processing, the MergeResult object contains a sorted list of UnresolvedPlaceholders, and the CLI writes a warning to stderr. This allows you to identify missing data keys without breaking the document generation process.
Does OfficeCLI support recursive placeholder replacement within replaced values?
No. The SinglePassReplace method executes the regex exactly once per text segment and does not feed replacement results back into the regex engine. This design prevents accidental recursive expansion and ensures that literal text containing curly braces in your JSON values remains unchanged.
Can I use the merge functionality programmatically without the CLI?
Yes. The TemplateMerger class in src/officecli/Core/TemplateMerger.cs exposes public static methods including ParseMergeData and Merge that you can call directly from C# code. This allows integration into .NET applications, automated build pipelines, or custom document generation services without spawning command-line processes.
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 →