When to Use OfficeCLI Raw XML Access (L3) Instead of DOM Operations
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, the codebase falls back to raw-set when a typed setter encounters a property it cannot express.
# 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 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, 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 (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.
# 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 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 |
Command dispatcher; routes "raw" and "raw-set" verbs to the XML bypass path |
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 |
Contains fallback logic from typed setters to raw-set for unknown properties |
src/officecli/Handlers/WordHandler.cs |
Documents raw-set usage for verbatim XML preservation |
In ResidentServer.cs, the dispatcher checks the verb prefix to decide execution strategy:
// 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 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:
-
Attempt the DOM first. Use
set,add, or other typed commands for standard operations. -
Watch for failure modes. The CLI reports "property not found," or you observe that attributes are stripped or altered in the output.
-
Switch to
raw-set. Construct the exact XML needed and specify the insertion point via XPath. -
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-setcommand inCommandBuilder.Raw.csprovides the entry point for verbatim XML injection ResidentServer.csroutes commands to the appropriate level based on verb detection- Use
--action embed-binarywithraw-setfor 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 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.
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 →