Merging documents causing bullets to move

Hi, Our customer reported merging templates with bullets (with their letterhead) is causing an issue. The picture below shows the result:-
With no letterhead selected the document merges fine with the bullets aligning as they should:-
When in their template I can see that there is an indent that is in place just beside the number 13 (the template is attached so you can see for yourself)


When I double click on the indent the following pops up and I have worked out that is you clear the indent on each line of the bullet points then when you upload the template without indents it merges fine. To clear the indent, I double click on it and use the clear all button.
When the indents are removed from the template then it merges fine with the Letterhead. Why should the introduction of letterhead cause the indent to take this course of action?

In our code we set KEEP_SOURCE_FORMATTING but looks like that is not considered.
Can you please advice how we can fix this issue.
letterhead.docx (69.8 KB)

maintemplate.docx (29.5 KB)

This is our code how we merge documents:

if (applyHeader) {
				if ( (Array.isArray(headerFile) && headerFile.length !== 0) || (typeof headerFile === 'string' && headerFile.trim().length > 0)) {
					var headerDoc = new Document(headerFile.toString(), options);

					updatedDocument = new Document();
					builder2 = new DocumentBuilder(updatedDocument.getDocument());
					builder2.insertDocument(doc, ImportFormatMode.KEEP_DIFFERENT_STYLES);

					var hbuilder = new DocumentBuilder(headerDoc.getDocument());
					var headerPageNr = hbuilder.getDocument().getPageCount();

					mergeHeaderFooter(hbuilder, builder2, true, sameHeaderFooterFile, useHeaderFirstPageOnly, useFooterFirstPageOnly, nrPages, headerPageNr, pageSetup)
				}
			}

function mergeHeaderFooter(sourceBuilder, destBuilder, isHeader, isFooter, firstPageOnly, firstPageOnlyFooter, nrPages, footerPageNr, pageSetup) {
	var fbuilderfooter = null;

	var sections = destBuilder.getDocument().getSections();
	if (sections) {
		var sectionCount = sections.getCount();
		if (firstPageOnly && firstPageOnlyFooter) {
			sectionCount = 1
		}

		for (var index = 0; index < sectionCount; index++) {
			/**@type {Packages.com.aspose.words.Section}*/
			var section = sections.get(index);

			//set margins from header/footer file to the destination file
			if (isFooter) {
				if (section.getPageSetup().getBottomMargin() < sourceBuilder.getPageSetup().getBottomMargin()) {
					section.getPageSetup().setBottomMargin(sourceBuilder.getPageSetup().getBottomMargin());
				}
				section.getPageSetup().setFooterDistance(sourceBuilder.getPageSetup().getFooterDistance());
			}
			if (isHeader) {
				if (section.getPageSetup().getTopMargin() < sourceBuilder.getPageSetup().getTopMargin()) {
					section.getPageSetup().setTopMargin(sourceBuilder.getPageSetup().getTopMargin());
				}
				if (pageSetup) {
					if (pageSetup.copyLeftRightMarginHeaderDocument) {
						section.getPageSetup().setRightMargin(sourceBuilder.getPageSetup().getRightMargin());
						section.getPageSetup().setLeftMargin(sourceBuilder.getPageSetup().getLeftMargin());
					}
				}
				section.getPageSetup().setHeaderDistance(sourceBuilder.getPageSetup().getHeaderDistance());
			}

			if (index == 0) {
				if (firstPageOnly || firstPageOnlyFooter) {
					section.getPageSetup().setDifferentFirstPageHeaderFooter(true);
				} else {
					if (isFooter && section.getPageSetup().getDifferentFirstPageHeaderFooter() && !sourceBuilder.getPageSetup().getDifferentFirstPageHeaderFooter()) {
						section.getPageSetup().setDifferentFirstPageHeaderFooter(sourceBuilder.getPageSetup().getDifferentFirstPageHeaderFooter());
					} else {
						section.getPageSetup().setDifferentFirstPageHeaderFooter(sourceBuilder.getPageSetup().getDifferentFirstPageHeaderFooter());
					}
				}
			}

			if (isHeader) {
				/**@type {Packages.com.aspose.words.HeaderFooter}*/
				var currFooter = section.getHeadersFooters().getByHeaderFooterType(headerFooterType.HEADER_FIRST);
				if (firstPageOnly || firstPageOnlyFooter) {
					fbuilderfooter = sourceBuilder.getCurrentSection().getHeadersFooters().getByHeaderFooterType(headerFooterType.HEADER_PRIMARY);
				} else {
					fbuilderfooter = sourceBuilder.getCurrentSection().getHeadersFooters().getByHeaderFooterType(headerFooterType.HEADER_FIRST);
				}
				if (fbuilderfooter != null) {
					if (currFooter == null) {
						// There is no header of the specified type in the current section, create it.
						currFooter = new HeaderFooter(destBuilder.getDocument(), headerFooterType.HEADER_FIRST);
						section.getHeadersFooters().add(currFooter);
					}
					currFooter.removeAllChildren();
					for (var i2 = fbuilderfooter.getChildNodes(NodeType.ANY, false).getCount() - 1; i2 >= 0; i2--) {
						var node = fbuilderfooter.getChildNodes(NodeType.ANY, false).get(i2);
						var importnode = destBuilder.getDocument().importNode(node, true, ImportFormatMode.KEEP_SOURCE_FORMATTING);
						//					if (footerPageNr > 1) {
						//						currFooter.appendChild(importnode);
						//					} else {
						currFooter.prependChild(importnode);
						//					}
					}
				}
			}
			if (isFooter) {
				var currFooter = section.getHeadersFooters().getByHeaderFooterType(headerFooterType.FOOTER_FIRST);
				if (firstPageOnly || firstPageOnlyFooter) {
					fbuilderfooter = sourceBuilder.getCurrentSection().getHeadersFooters().getByHeaderFooterType(headerFooterType.FOOTER_PRIMARY);
				} else {
					fbuilderfooter = sourceBuilder.getCurrentSection().getHeadersFooters().getByHeaderFooterType(headerFooterType.FOOTER_FIRST);
				}
				if (fbuilderfooter != null) {
					if (currFooter == null) {
						// There is no header of the specified type in the current section, create it.
						currFooter = new HeaderFooter(destBuilder.getDocument(), headerFooterType.FOOTER_FIRST);
						section.getHeadersFooters().add(currFooter);
					}
					currFooter.removeAllChildren();
					for (var i2 = fbuilderfooter.getChildNodes(NodeType.ANY, false).getCount() - 1; i2 >= 0; i2--) {
						var node = fbuilderfooter.getChildNodes(NodeType.ANY, false).get(i2);
						var importnode = destBuilder.getDocument().importNode(node, true, ImportFormatMode.KEEP_SOURCE_FORMATTING);
						currFooter.prependChild(importnode);
					}
				}
			}

			if (!firstPageOnly) {
				if (isHeader) {
					var currFooter = section.getHeadersFooters().getByHeaderFooterType(headerFooterType.HEADER_PRIMARY);
					fbuilderfooter = sourceBuilder.getCurrentSection().getHeadersFooters().getByHeaderFooterType(headerFooterType.HEADER_PRIMARY);
					if (fbuilderfooter != null) {
						if (currFooter == null) {
							// There is no header of the specified type in the current section, create it.
							currFooter = new HeaderFooter(destBuilder.getDocument(), headerFooterType.HEADER_PRIMARY);
							section.getHeadersFooters().add(currFooter);
						}
						currFooter.removeAllChildren();
						for (var i2 = fbuilderfooter.getChildNodes(NodeType.ANY, false).getCount() - 1; i2 >= 0; i2--) {
							var node = fbuilderfooter.getChildNodes(NodeType.ANY, false).get(i2);
							var importnode = destBuilder.getDocument().importNode(node, true, ImportFormatMode.KEEP_SOURCE_FORMATTING);
							currFooter.prependChild(importnode);
						}
					}
				}
			}
			if (!firstPageOnlyFooter) {
				if (isFooter) {
					var currFooter = section.getHeadersFooters().getByHeaderFooterType(headerFooterType.FOOTER_PRIMARY);
					fbuilderfooter = sourceBuilder.getCurrentSection().getHeadersFooters().getByHeaderFooterType(headerFooterType.FOOTER_PRIMARY);
					if (fbuilderfooter != null) {
						if (currFooter == null) {
							// There is no header of the specified type in the current section, create it.
							currFooter = new HeaderFooter(destBuilder.getDocument(), headerFooterType.FOOTER_PRIMARY);
							section.getHeadersFooters().add(currFooter);
						}
						currFooter.removeAllChildren();
						for (var i2 = fbuilderfooter.getChildNodes(NodeType.ANY, false).getCount() - 1; i2 >= 0; i2--) {
							var node = fbuilderfooter.getChildNodes(NodeType.ANY, false).get(i2);
							var importnode = destBuilder.getDocument().importNode(node, true, ImportFormatMode.KEEP_SOURCE_FORMATTING);
							currFooter.prependChild(importnode);
						}
					}
				}
			}
			if (!firstPageOnly) {
				if (isHeader) {
					var currFooter = section.getHeadersFooters().getByHeaderFooterType(headerFooterType.HEADER_EVEN);
					fbuilderfooter = sourceBuilder.getCurrentSection().getHeadersFooters().getByHeaderFooterType(headerFooterType.HEADER_EVEN);
					if (fbuilderfooter != null) {
						if (currFooter == null) {
							// There is no header of the specified type in the current section, create it.
							currFooter = new HeaderFooter(destBuilder.getDocument(), headerFooterType.HEADER_EVEN);
							section.getHeadersFooters().add(currFooter);
						}
						currFooter.removeAllChildren();
						for (var i2 = fbuilderfooter.getChildNodes(NodeType.ANY, false).getCount() - 1; i2 >= 0; i2--) {
							var node = fbuilderfooter.getChildNodes(NodeType.ANY, false).get(i2);
							var importnode = destBuilder.getDocument().importNode(node, true, ImportFormatMode.KEEP_SOURCE_FORMATTING);
							currFooter.prependChild(importnode);
						}
					}
				}
			}
			if (!firstPageOnlyFooter) {
				if (isFooter) {
					var currFooter = section.getHeadersFooters().getByHeaderFooterType(headerFooterType.FOOTER_EVEN);
					fbuilderfooter = sourceBuilder.getCurrentSection().getHeadersFooters().getByHeaderFooterType(headerFooterType.FOOTER_EVEN);
					if (fbuilderfooter != null) {
						if (currFooter == null) {
							// There is no header of the specified type in the current section, create it.
							currFooter = new HeaderFooter(destBuilder.getDocument(), headerFooterType.FOOTER_EVEN);
							section.getHeadersFooters().add(currFooter);
						}
						currFooter.removeAllChildren();
						for (var i2 = fbuilderfooter.getChildNodes(NodeType.ANY, false).getCount() - 1; i2 >= 0; i2--) {
							var node = fbuilderfooter.getChildNodes(NodeType.ANY, false).get(i2);
							var importnode = destBuilder.getDocument().importNode(node, true, ImportFormatMode.KEEP_SOURCE_FORMATTING);
							currFooter.prependChild(importnode);
						}
					}
				}
			}
		}
	}

	return;
}

@minaeimi

What is happening?

When Aspose.Words merges two DOCX files it tries to keep the character formatting of the source document (ImportFormatMode.KeepSourceFormatting).
Paragraph‑level formatting (styles, indents, list definitions) is not guaranteed to stay unchanged if the destination document already contains a style with the same name or a list with the same ID.

In your letter‑head document a paragraph style (usually Normal) has a left‑indent set in its ParagraphFormat.
When the two documents are combined the bullet paragraphs from the main template are mapped to that same style, so the left‑indent from the letter‑head overrides the bullet‑list indent that you see in the original template. The result is the “shifted” bullet you posted.


How to fix it

Below are a few practical ways to keep the bullet indentation exactly as it is in the source template.

1. Preserve the source list definition explicitly

import com.aspose.words.*;

public class MergeWithBullets {
    public static void main(String[] args) throws Exception {

        // Load the two documents
        Document mainTemplate = new Document("maintemplate.docx");
        Document letterHead   = new Document("letterhead.docx");

        // -------------------------------------------------
        // 1) Clone the list definition(s) from the source
        // -------------------------------------------------
        for (List srcList : letterHead.getLists()) {
            // Deep‑clone the list and add it to the destination
            List cloned = (List) srcList.deepClone(true);
            mainTemplate.getLists().add(cloned);
        }

        // -------------------------------------------------
        // 2) Append the letter‑head (keep source formatting)
        // -------------------------------------------------
        mainTemplate.appendDocument(letterHead, ImportFormatMode.KeepSourceFormatting);

        // -------------------------------------------------
        // 3) Refresh list numbering – makes sure the
        //    indents that belong to the list are applied
        // -------------------------------------------------
        mainTemplate.updateListLabels();

        // -------------------------------------------------
        // 4) Save the result
        // -------------------------------------------------
        mainTemplate.save("merged_result.docx");
    }
}

Why this works

  • The list (including its ListLevel objects that store the left‑indent) is cloned before the append operation, so the destination document now contains an identical list definition.
  • updateListLabels() forces Word to recompute the list layout based on the newly added list, which restores the original bullet indents.

2. Use a dedicated paragraph style for the bullet list

If you can modify the source template, give the bullet paragraphs their own style (e.g. MyBulletList).
Make sure this style does not inherit a left‑indent from the base style.

// Example – creating a custom bullet style (run once)
Style bulletStyle = mainTemplate.getStyles().addEffectiveStyle("MyBulletList");
bulletStyle.getParagraphFormat().setLeftIndent(0);   // explicit left indent
bulletStyle.getListFormat().setList(mainTemplate.getLists().get(0));

When the style is unique, Aspose will not map the paragraphs to the Normal style that carries the letter‑head indent, and the bullets stay in place.


3. Strip/override the left indent that comes from the letter‑head

If you cannot change the source files, you can clean the unwanted indent after the merge:

for (Paragraph para : mainTemplate.getChildNodes(NodeType.PARAGRAPH, true)) {
    // Check that the paragraph is part of a list
    if (para.isListItem()) {
        // Reset the left indent to the value you expect (e.g., 0.25")
        para.getParagraphFormat().setLeftIndent(0.25);
    }
}
mainTemplate.updateListLabels();

This approach is handy when the same merge logic is used for many documents and you simply want to enforce a known indent value.


Quick checklist before merging

Step What to verify
Styles The bullet list uses a style that does not inherit a left‑indent from the base (e.g., Normal).
List IDs No two lists in the combined document share the same list ID unless they are intended to be the same list.
Import mode Use ImportFormatMode.KeepSourceFormatting and clone the source list definitions (as shown above).
Post‑merge Call document.updateListLabels(); to force re‑calculation of list layout.

What to do next?

  1. Try the list‑cloning approach (Solution 1) – it solves the problem in the majority of cases where a conflicting style/indent is present in the header/footer document.
  2. If you prefer a style‑based solution, create a dedicated bullet style in the template (Solution 2).
  3. If you need a quick “post‑process” fix, reset the left indent after the merge (Solution 3).

If after applying these steps the bullets still shift, please attach the exact source files you are using (the ones you posted are fine, but a minimal reproducible example helps us verify the list IDs and style hierarchy). With that we can run a precise test and give you the exact code‑snippet that works for your scenario.


Reference links

Feel free to reach out with any follow‑up questions or to share the updated files for further analysis. Happy coding!

@minaeimi Please try cloning the original document and use it as the target document instead of creating document from scratch:

// Clone the original document to keep settings. and styles
Document updatedDocument = (Document) doc.deepClone(false); updatedDocument.ensureMinimum();
DocumentBuilder builder2 = new DocumentBuilder(updatedDocument);
builder2.insertDocument(doc, ImportFormatMode.KEEP_DIFFERENT_STYLES);