How does UniOffice use Word templates?
“Template” means two different things here, and the calls involved have nothing to do with each other.
One is a .docx you open for its styles, headers and numbering and then write
fresh content into. The other is a .docx whose layout and wording are already
final, carrying marked slots your program fills in. Most people mean the second.
Opening a document for its styles
document.OpenTemplate opens a file and discards its body, leaving the styles
available for content you add:
doc, err := document.OpenTemplate("template.docx")
if err != nil {
log.Fatalf("error opening template: %s", err)
}
defer doc.Close()
para := doc.AddParagraph()
para.SetStyle("Heading1")
para.AddRun().AddText("Generated heading")Word removes unused styles when it saves, so a template needs a paragraph using every style you intend to apply, or the style will not be there when you ask for it. Clearing the body also clears the section properties attached to it, so page size, orientation, margins and the header and footer references go with the content. If the template’s headers matter, reattach them after opening.
Filling a prepared document
Here the layout stays and you replace the slots. What differs between templates is how those slots are marked, and that choice belongs to whoever built the file.
| Marker | Filled with | Reaches headers and footers | Survives editing in Word |
|---|---|---|---|
| Merge fields | doc.MailMerge(map[string]string) | Yes | Yes. Word tracks them as fields. |
{{PLACEHOLDER}} strings | Your own walk over doc.Paragraphs() | No | Partly, see below. |
| Content controls | doc.StructuredDocumentTags(), matched by Tag() | Yes | Yes, and they can be locked. |
Merge fields are the most capable. MailMerge finds them in body paragraphs,
table cells, headers and footers, applies each field’s own formatting switches to
your value, and clears the document’s mail merge settings so the saved file does
not prompt to reconnect to a data source:
doc.MergeFields() // what this template expects
doc.MailMerge(map[string]string{
"FirstName": "Alice",
"Company": "Example Ltd",
})Every field found is consumed whether or not your map has a key for it, so a
field you leave out is blanked rather than left in place. Supply every name
MergeFields returns, using an empty string where you want nothing.
Placeholder strings are the easiest to produce and the most fragile to consume.
Word is free to split {{TITLE}} across several runs, and does so routinely
after an edit with no visible difference. A substitution that works on the
template you were given can quietly stop matching after someone opens and saves
it.
Content controls avoid that, because Word stores them as objects with a stable tag rather than as text you have to find. If you own the template as well as the code, build it around those.
The templates and mail merge guides cover each of the three in full, and content controls covers the third.