# How to Use the OfficeCLI Merge Command for Batch Report Generation from Templates

> Learn to use the OfficeCLI merge command for powerful batch report generation. Effortlessly populate DOCX XLSX or PPTX templates with JSON data to create customized documents at scale.

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

---

**The OfficeCLI merge command replaces `{{key}}` placeholders in DOCX, XLSX, or PPTX templates with JSON data values to generate customized documents individually or at scale through batch processing.**

The **iOfficeAI/OfficeCLI** repository provides a cross-platform .NET CLI tool for automating Microsoft Office document operations. The `merge` command serves as the core engine for template-based report generation, enabling developers to transform static templates into dynamic documents using structured JSON data sources.

## Understanding the Merge Command Architecture

The merge functionality is implemented across several core files in the `src/officecli/` directory, with clear separation between command parsing, data processing, and document manipulation.

### Command Definition and Argument Parsing

In [`src/officecli/CommandBuilder.Import.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/CommandBuilder.Import.cs) (lines 77-84), the command is constructed with required positional arguments for template and output paths, plus essential options:

```csharp
var mergeTemplateArg = new Argument<string>("template") { Description = "Template file path (.docx, .xlsx, .pptx) with {{key}} placeholders" };
var mergeOutputArg   = new Argument<string>("output")   { Description = "Output file path" };
var mergeDataOpt    = new Option<string>("--data")      { Description = "JSON data or path to .json file", Required = true };
var mergeForceOpt   = new Option<bool>("--force")       { Description = "Overwrite an existing output file." };
var mergeCommand = new Command("merge", "Merge template with JSON data, replacing {{key}} placeholders");

```

The command requires exactly two positional arguments: the **template** file path and the **output** file path. The `--data` option is mandatory and accepts either inline JSON or a path to a `.json` file.

### Resident Synchronization Mechanism

Before processing begins, the system ensures data consistency through the resident server architecture. In [`CommandBuilder.Import.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/CommandBuilder.Import.cs) (lines 98-102), the code invokes `ResidentClient.SendSave()` to flush any in-memory edits to disk:

```csharp
ResidentClient.SendSave(Path.GetFullPath(template));

```

This guarantees the merge operation works against the latest version of the template, preventing race conditions when templates are actively being edited.

## JSON Data Processing and Flattening

The `TemplateMerger.ParseMergeData` method in [`src/officecli/Core/TemplateMerger.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/Core/TemplateMerger.cs) (lines 39-50 and 66-88) handles data interpretation with intelligent file detection:

- If the `--data` argument ends with `.json` and the file exists, it reads from disk
- Otherwise, it parses the string as inline JSON text

The method flattens nested objects and arrays into dot and bracket notation keys. For example, `{"user": {"name": "Alice"}, "items": ["a", "b"]}` becomes `user.name`, `items[0]`, and `items[1]`. Literal top-level keys maintain precedence over flattened equivalents.

## Document Format Support and Placeholder Replacement

The `TemplateMerger.Merge` method (lines 57-84) guards against accidental overwrites—rejecting existing output files unless `--force` is specified—then dispatches to format-specific implementations based on file extension:

```csharp
if (File.Exists(outputPath) && !force) … // guard against accidental overwrite
File.Copy(templatePath, outputPath, overwrite: true);
var ext = Path.GetExtension(outputPath).ToLowerInvariant();
return ext switch {
    ".docx" => MergeDocx(outputPath, data),
    ".xlsx" => MergeXlsx(outputPath, data),
    ".pptx" => MergePptx(outputPath, data),
    _ => throw new CliException(...),
};

```

### DOCX Processing Details

For Word documents, `MergeDocx` processes every `<w:t>` text node in the document XML. The implementation uses a single-pass regular expression defined by `PlaceholderPattern` (lines 28-34) that matches `{{ … }}` syntax while allowing hyphens, dots, array indexes, and inner spaces. Each match resolves against the flattened data dictionary; unresolved placeholders are tracked for reporting.

## Batch Report Generation Workflows

While single merges work for individual documents, the `batch` command enables automated report generation at scale.

### Single Document Generation

Execute a one-off merge using the `import merge` subcommand:

```bash
officecli import merge \
    templates/EmployeeSummary.docx \
    output/EmployeeSummary_2024.docx \
    --data '{"name":"Alice","department":"Engineering","salary":"120k"}'

```

For external data files with force overwrite:

```bash
officecli import merge \
    templates/Invoice.docx \
    output/Invoice_2024.docx \
    --data data/invoice-2024.json \
    --force

```

### Processing Multiple Reports via Batch Command

The `batch` command in [`src/officecli/CommandBuilder.Batch.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/CommandBuilder.Batch.cs) (lines 26-31) accepts a JSON array of operations. Each object requires a `"command"` field set to `"merge"` plus the standard merge parameters:

```json
[
  {
    "command": "merge",
    "template": "templates/QuarterlyReport.docx",
    "output":   "reports/Q1.docx",
    "data":     "{\"quarter\":\"Q1\",\"sales\":125000}"
  },
  {
    "command": "merge",
    "template": "templates/QuarterlyReport.docx",
    "output":   "reports/Q2.docx",
    "data":     "{\"quarter\":\"Q2\",\"sales\":147500}"
  }
]

```

Execute the batch using file input:

```bash
officecli batch myReport.docx --commands @batch.json

```

Or pipe JSON directly via stdin:

```bash
cat <<'EOF' | officecli batch myWorkbook.xlsx --commands -
[
  {
    "command":"merge",
    "template":"templates/FinancialSummary.xlsx",
    "output":"reports/Financial_Q1.xlsx",
    "data":"{\"quarter\":\"Q1\",\"revenue\":850000}"
  },
  {
    "command":"merge",
    "template":"templates/FinancialSummary.xlsx",
    "output":"reports/Financial_Q2.xlsx",
    "data":"{\"quarter\":\"Q2\",\"revenue\":910000}"
  }
]
EOF

```

## Output and Error Reporting

When invoked with `--json`, the command emits a structured JSON object (lines 106-133 in [`CommandBuilder.Import.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/CommandBuilder.Import.cs)) containing:
- `output`: The generated file path
- `replacedKeys`: Array of successfully substituted placeholders
- `unresolvedPlaceholders`: Array of keys not found in the data source

Standard mode provides human-readable summaries to stdout/stderr, including warnings for any placeholders that could not be resolved.

## Summary

- **The OfficeCLI merge command** processes DOCX, XLSX, and PPTX templates containing `{{key}}` placeholders, substituting values from JSON data sources
- **Command architecture** spans [`CommandBuilder.Import.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/CommandBuilder.Import.cs) for CLI parsing, [`ResidentClient.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/ResidentClient.cs) for file synchronization, and [`TemplateMerger.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/TemplateMerger.cs) for data processing and document generation
- **Data flattening** supports nested objects and arrays via dot notation (e.g., `user.name`) and bracket notation (e.g., `items[0]`)
- **Batch processing** enables automated multi-document generation through the `batch` command using JSON command arrays
- **Safety features** include resident synchronization to prevent stale data and overwrite protection via the `--force` flag

## Frequently Asked Questions

### What placeholder syntax does OfficeCLI merge support?

OfficeCLI uses double curly brace syntax: `{{key}}`. The regex pattern defined in [`TemplateMerger.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/TemplateMerger.cs) (lines 28-34) allows hyphens, dots, array indexes, and spaces within the braces, supporting keys like `{{user.name}}` or `{{items[0].title}}`.

### Can I merge data from external JSON files?

Yes. Pass a file path ending in `.json` to the `--data` option instead of inline JSON. The `ParseMergeData` method automatically detects file paths versus raw JSON strings and reads the file contents when appropriate.

### How does the batch command differ from running multiple merge commands?

The `batch` command accepts a JSON array of operations via stdin or file input, executing them sequentially against the same resident server session. This reduces overhead compared to spawning separate CLI processes and ensures consistent state across multiple merge operations, as implemented in [`CommandBuilder.Batch.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/CommandBuilder.Batch.cs) (lines 26-31).

### What happens if a placeholder in my template has no matching data key?

Unresolved placeholders are collected during processing and reported in the output. When using `--json`, they appear in the `unresolvedPlaceholders` array; in standard mode, they are listed in the console summary. The original placeholder text remains in the generated document.