Additional Bookmarks Added During Aspose Document Generation

We are using Aspose for document generation. In our Word template, we have only one bookmark defined. However, when we generate the document through Aspose, the output document contains additional bookmarks (for example, the bookmark count increases from 1 to 8). These extra bookmarks are not expected and are causing issues in our downstream processing.

We are observing this behavior across multiple templates, not just a single file.

We would like to understand:

  1. Why are these additional bookmarks being created during document generation?
  2. Is this expected behavior due to Aspose handling or converting internal structure?
  3. How can we prevent or suppress these extra bookmarks and retain only the original bookmarks defined in the template?

@sfulari

Why extra bookmarks appear after Aspose.Words generation?

When a .doc/.docx file is loaded or saved by Aspose.Words, the library preserves all bookmark nodes that exist in the Word package – including the hidden system bookmarks that are automatically created by Microsoft Word itself.

Typical hidden bookmarks that you will see in the Bookmarks collection are:

Hidden bookmark name When it is created
_GoBack Created by Word for the Go‑Back command.
_Footnote / _Endnote Added when a footnote/endnote exists.
_Toc* Generated for a Table‑of‑Contents field.
_Picture* Added for inline pictures, charts, etc.
_Hyperlink* Produced when a hyperlink is inserted.
_ContentControl* For structured‑document‑tags (SDT).

These bookmarks are not visible in the Word UI (they are marked as hidden), but they are part of the OpenXML package. Aspose.Words faithfully loads them and, unless you explicitly remove them, they are written back when the document is saved. This is why a template that originally contains one user‑defined bookmark can end up with 8, 10, … bookmarks after processing.

Is this behaviour expected?

Yes. Aspose.Words does not create any additional bookmarks on its own; it merely preserves the ones that already exist in the source document – including the hidden ones described above. This is the default and documented behaviour of the library.

Reference: Aspose.Words – Working with Bookmarks


How to keep only the original (user‑defined) bookmarks?

There are two common strategies:

  1. Remove unwanted bookmarks after the document is generated.
  2. Prevent hidden bookmarks from being added in the first place (when possible).

Below are code samples for both approaches.

1. Removing unwanted bookmarks after generation

using Aspose.Words;

// Load the template
Document doc = new Document("Template.docx");

// *** Your document generation logic here ***
// e.g. mail‑merge, DocumentBuilder, etc.

// -----------------------------------------------------------
// 1️⃣ Capture the list of *known* (user‑defined) bookmark names
HashSet<string> wanted = new HashSet<string>();
foreach (Bookmark bm in doc.Range.Bookmarks)
{
    // Keep only bookmarks that do NOT start with an underscore (_) 
    // – most hidden bookmarks use this convention.
    if (!bm.Name.StartsWith("_"))
        wanted.Add(bm.Name);
}

// -----------------------------------------------------------
// 2️⃣ Remove every bookmark that is NOT in the wanted list
for (int i = doc.Range.Bookmarks.Count - 1; i >= 0; i--)
{
    Bookmark bm = doc.Range.Bookmarks[i];
    if (!wanted.Contains(bm.Name))
    {
        // Remove the bookmark node pair (Start/End)
        bm.Remove();
    }
}

// -----------------------------------------------------------
// 3️⃣ Save the final document
doc.Save("Result.docx");

Why iterate backwards?
Bookmarks.Remove() modifies the collection, so iterating from the end prevents index‑out‑of‑range exceptions.

Tip: If you need to keep all user‑defined bookmarks regardless of their naming pattern, record the names before you start any generation work (e.g., right after loading the template) and use that list for the filter.

2. Suppressing hidden bookmarks during generation (when possible)

Scenario What you can do
Inserting a Table‑of‑Contents Use doc.UpdateFields() after you have finished editing. The TOC creates its own hidden bookmarks (_Toc*). If you don’t need a TOC, simply skip the InsertTableOfContents call.
Inserting Hyperlinks Prefer DocumentBuilder.InsertHyperlink(string text, string url, bool isUrlAbsolute) – this does not generate a hidden bookmark unless you explicitly request a bookmark target.
Adding Pictures/Charts Insert images via DocumentBuilder.InsertImage(...). The library does not create hidden bookmarks for the image itself.
Mail‑Merge Use MailMerge.Execute(... ) without the Options.UseLegacyMergeFieldProcessing flag – the legacy mode may add temporary bookmarks that are later removed automatically, but the modern mode keeps the source structure intact.

If you cannot avoid a specific operation that creates hidden bookmarks (e.g., a TOC is required), the post‑generation clean‑up shown in section 1 remains the reliable way to keep only the bookmarks you care about.


Quick checklist for your project

:white_check_mark: Action
1 After loading the template, store the list of user‑defined bookmark names (doc.Range.Bookmarks).
2 Run all your generation code (mail‑merge, DocumentBuilder, etc.).
3 Iterate backwards through doc.Range.Bookmarks and remove every bookmark whose name is not in the stored list.
4 Save the document.
5 (Optional) If you notice a particular operation always adds a specific hidden bookmark, consider adjusting the code as described in the table above.

References

If you need a concrete example tailored to the exact generation steps you are using (e.g., mail‑merge, InsertHtml, etc.), feel free to share that snippet and I’ll provide a focused code sample. Happy coding!

@sfulari Could you please attach your problematic input and output documents along with code that will allow us to reproduce the problem? We will check the issue and provide you more information.