# When to Use OfficeCLI Raw XML Access (L3) Instead of DOM Operations

> Learn when to use OfficeCLI raw XML access L3 over DOM operations for unsupported attributes, perfect round trips, bulk updates, or binary data. Optimize your Office CLI usage.

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

---

**Use OfficeCLI raw XML access (L3) when you need unsupported OOXML attributes, perfect round-trip fidelity, performance-critical bulk updates, or binary data embedding that the typed DOM (L2) cannot handle.**

Most Office document editing tasks should use the Level 2 DOM API for its type safety and validation. However, certain edge cases require dropping to Level 3 raw XML to manipulate the underlying Open XML directly. This guide explains the architectural distinction between these two approaches and provides clear criteria for choosing raw XML access in the iOfficeAI/OfficeCLI codebase.

## Understanding the Two-Level Architecture

OfficeCLI implements a two-tiered command system for modifying Office documents. The **Level 2 DOM** provides a strongly-typed, semantic API that abstracts Open XML complexity. The **Level 3 raw XML** layer bypasses this abstraction entirely, letting you inject or replace XML fragments verbatim.

This split exists because the DOM cannot practically expose every OOXML element, attribute, and edge case. Raw XML access fills these gaps without bloating the typed API.

### Level 2: The DOM (Typed API)

The DOM parses Open XML into an object model with high-level operations (`set`, `add`, `remove`, `move`). You reference properties by semantic names like `bold`, `fontSize`, or `tableBorders`.

Choose the DOM when:

- Performing routine formatting (text, tables, images, fields)
- You want compile-time validation and IDE auto-completion
- The element you need is already implemented in the DOM

### Level 3: Raw XML Access (`raw-set`)

The `raw-set` command sends your exact XML payload directly into the document package at a specified XPath. No parsing or re-serialization occurs.

Choose raw XML access when:

- The DOM does **not** expose a required element or property
- You need **perfect round-trip fidelity** for content the DOM would rewrite
- Performing **performance-critical bulk updates** that must avoid DOM overhead
- Embedding or manipulating **binary data** the DOM cannot represent

## When Raw XML Access Becomes Necessary

The OfficeCLI source code explicitely routes certain operations to the raw XML path. Understanding these triggers helps you recognize when to skip the DOM entirely.

### Unsupported Schema Elements

Custom XML parts, obscure OOXML attributes, and new schema extensions often lack DOM support. In [`WordHandler.Set.Dispatch.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.Set.Dispatch.cs), the codebase falls back to `raw-set` when a typed setter encounters a property it cannot express.

```bash

# DOM fails: custom w:myCustomAttr not exposed by the typed API

officecli set mydoc.docx /body/p[1] --prop myCustomAttr=42

# Error: property not found

# L3 raw-set succeeds: inject the exact XML needed

officecli raw-set /body/p[1] --xpath "./w:p" \
    --xml '<w:p><w:r><w:t>Hello</w:t></w:r><w:myCustomAttr w:val="42"/></w:p>'

```

The `raw-set` implementation in [`CommandBuilder.Raw.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/CommandBuilder.Raw.cs) accepts an explicit XPath and XML payload, writing it verbatim without DOM transformation.

### Round-Trip Fidelity Requirements

The DOM normalizes and re-serializes content, which can alter whitespace, attribute ordering, or unrecognized markup. For embedded binary blobs, custom VML, or legacy markup, this rewriting risks data corruption.

In [`WordHandler.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.cs), the documentation notes that `raw-set` preserves "verbatim XML" when the structured API would otherwise modify content. Use raw XML access when any DOM transformation is unacceptable.

### Performance-Critical Bulk Operations

DOM operations incur parsing and re-serialization overhead for the entire document. For large-scale updates where you can construct targeted XML fragments, raw XML access avoids this cost.

The command dispatcher in [`ResidentServer.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/ResidentServer.cs) (line 1118) branches to the raw XML path for `"raw"` and `"raw-set"` verbs specifically to support these high-throughput scenarios.

### Binary Data Embedding

The DOM cannot represent arbitrary binary data. OfficeCLI's `embed-binary` action works exclusively through raw XML access, attaching binary files as OOXML relationships.

```bash

# L3: embed a binary payload as a custom XML part

officecli raw-set /customXml --action embed-binary \
    --xml '<my:customXmlPart xmlns:my="http://example.com"><my:data/></my:customXmlPart>' \
    --binary-file ./payload.bin

```

This pattern appears in [`ResidentServer.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/ResidentServer.cs) where the raw path handles `embed-binary` actions that the DOM has no equivalent for.

## Source Code Implementation Details

The architectural split between L2 and L3 is enforced at multiple points in the codebase:

| File | Role |
|------|------|
| [`src/officecli/ResidentServer.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/ResidentServer.cs) | Command dispatcher; routes `"raw"` and `"raw-set"` verbs to the XML bypass path |
| [`src/officecli/CommandBuilder.Raw.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/CommandBuilder.Raw.cs) | Implements `raw` and `raw-set` verb handlers; accepts XPath and XML payload |
| [`src/officecli/Handlers/Word/WordHandler.Set.Dispatch.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/Handlers/Word/WordHandler.Set.Dispatch.cs) | Contains fallback logic from typed setters to `raw-set` for unknown properties |
| [`src/officecli/Handlers/WordHandler.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/Handlers/WordHandler.cs) | Documents `raw-set` usage for verbatim XML preservation |

In [`ResidentServer.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/ResidentServer.cs), the dispatcher checks the verb prefix to decide execution strategy:

```csharp
// Simplified representation of the dispatch logic
if (verb == "raw" || verb == "raw-set")
{
    // Bypass DOM mutators; use raw XML handler
    ExecuteRawSet(command);
}
else
{
    // Route through typed DOM API
    ExecuteDomOperation(command);
}

```

The [`WordHandler.Set.Dispatch.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.Set.Dispatch.cs) file (line 1052) demonstrates this fallback in practice: even when a property seems DOM-compatible, the handler forces `raw-set` if the typed implementation cannot generate the required XML structure.

## Practical Decision Workflow

Follow this sequence when deciding between DOM and raw XML access:

1. **Attempt the DOM first.** Use `set`, `add`, or other typed commands for standard operations.

2. **Watch for failure modes.** The CLI reports "property not found," or you observe that attributes are stripped or altered in the output.

3. **Switch to `raw-set`.** Construct the exact XML needed and specify the insertion point via XPath.

4. **Verify round-trip integrity.** Confirm that raw XML access preserves your markup exactly as authored.

## Summary

- **Start with Level 2 DOM** for type safety, validation, and standard editing tasks
- **Drop to Level 3 raw XML access** when the DOM lacks support for required elements, perfect fidelity is mandatory, bulk performance matters, or binary data must be embedded
- The `raw-set` command in [`CommandBuilder.Raw.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/CommandBuilder.Raw.cs) provides the entry point for verbatim XML injection
- [`ResidentServer.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/ResidentServer.cs) routes commands to the appropriate level based on verb detection
- Use `--action embed-binary` with `raw-set` for binary payloads the DOM cannot handle

## Frequently Asked Questions

### How do I know if the DOM supports a specific OOXML element?

Attempt a standard `set` or `add` command with the property name. If OfficeCLI returns "property not found" or silently ignores the attribute, the DOM lacks support. Check [`WordHandler.Set.Dispatch.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.Set.Dispatch.cs) in the source for the current mapping of supported properties, or proceed directly to `raw-set` with your XML fragment.

### Can I mix DOM and raw XML operations in the same script?

Yes. OfficeCLI processes commands sequentially, so you can perform DOM operations for standard edits and intersperse `raw-set` commands for special cases. Each command commits changes to the document package before the next executes, ensuring consistent state.

### Does raw XML access bypass OfficeCLI's validation entirely?

Partially. `raw-set` validates that your XML is well-formed and that the XPath resolves to an existing location, but it does not validate against the OOXML schema. You are responsible for producing schema-compliant markup. This trade-off enables access to extensions and future schema versions the DOM has not yet implemented.

### Is raw XML access faster than the DOM for all operations?

Only for specific patterns. Raw XML avoids parse/serialize overhead when you construct targeted fragments manually. For single, simple edits, the DOM may be faster due to optimized internal caching. Profile your specific workload—bulk updates with pre-constructed XML favor raw access; scattered property changes favor the DOM.