Replacing placeholder using aspose word java api

Hello Team,

I tried upgrading the Aspose Words jar from version 2018 to 2025. While using the same code with both versions, I am encountering an issue in the latest jar.

In the 2018 jar version, the output is correct (please see attached output file – *
Output_Aspose_18.docx (127.0 KB)

*). However, when I use the 2025 jar version, the output is different (please see attached output file – *
Output_Aspose_25.docx (126.9 KB)

*).

Both tests were run using the same input file, but the results differ. The issue is specifically with the Title sequence number when replacing the placeholder SOWPH_Cancellation:

  • With the 2018 jar, the Title sequence number is correctly shown as 5.
  • With the 2025 jar, the Title sequence number incorrectly shows as 1.

Please find the input file here
1.
FPS_Template.docx (142.7 KB)

Clause_Cancel_EN.docx (18.7 KB)

Below is the code snippet I am using for both versions:

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Locale;
import java.util.regex.Pattern;

import com.aspose.words.Document;
import com.aspose.words.DocumentBuilder;
import com.aspose.words.FindReplaceOptions;
import com.aspose.words.IReplacingCallback;
import com.aspose.words.ImportFormatMode;
import com.aspose.words.License;
import com.aspose.words.Node;
import com.aspose.words.NodeType;
import com.aspose.words.ReplaceAction;
import com.aspose.words.ReplacingArgs;
import com.aspose.words.Run;

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

    	 System.out.println("Hello and completed!!!");
        Document targetDoc = new Document("D:\\ACA33\\Aspose\\FPS_Template.docx");
        Document clauseDoc = new Document("D:\\ACA33\\Aspose\\Clause_Cancel_EN.docx");
        ReplacingCallback callback = new ReplacingCallback(clauseDoc);
        FindReplaceOptions options1 = new FindReplaceOptions(callback);
		options1.setMatchCase(true);
		
		targetDoc.getRange().replace("SOWPH_Cancellation", "", options1);
	
		targetDoc.save("D:\\ACA33\\Aspose\\Output_Aspose_18.docx", com.aspose.words.SaveFormat.DOCX);
		System.out.println("Hello and completed finish!!!");
    }
    
    public static final String ASPOSE_LICENSE_FILE_PATH = "D:\\dsplm\\products\\3dexperience\\3dspace\\win_b64\\code\\tomee\\webapps\\3dspace\\WebClient\\Aspose.Words.lic";
	public static void initAsposeLicense() throws Exception {
		System.out.println("SOW_WordReplace_mxJPO: initAsposeLicense==============START");
		 System.out.println("SOW_WordReplace_mxJPO: initAsposeLicense==============ASPOSE_LICENSE_FILE_PATH="
				+ ASPOSE_LICENSE_FILE_PATH);
		InputStream license = new FileInputStream(ASPOSE_LICENSE_FILE_PATH);
		if (license != null) {
			License manager = new License();
			try {
				manager.setLicense(license);
				 System.out.println("SOW_WordReplace_mxJPO: initAsposeLicense=============setLicense=Done");
			} catch (Exception e) {
				 System.out.println("SOW_WordReplace_mxJPO:initAsposeLicense==============Error:unable to load the license");
			}
		} else {
			 System.out.println(
					"SOW_WordReplace_mxJPO:initAsposeLicense==============Error:no Aspose.Words.lic license found.");
		}

		 System.out.println("SOW_WordReplace_mxJPO:initAsposeLicense==============END");
	}
	
	static {
		Locale previous = Locale.getDefault();
		Locale.setDefault(Locale.US);
		try {
			AsposeTest.initAsposeLicense();
		} catch (Exception e) {
			System.err.println(
					"SOW_Util_mxJPO:Error: while calling static initializer in " + SOW_Util_mxJPO.class + " class:");
			e.printStackTrace();
			// throw e;
		} finally {
			Locale.setDefault(previous);
		}
	}
    
	static class ReplacingCallback implements IReplacingCallback {
		Document doc1;

		public ReplacingCallback(Document d) {
			doc1 = d;
		}

		@Override
		public int replacing(ReplacingArgs e) throws Exception {
			// This is a Run node that contains either the beginning or the complete match.
			Node currentNode = e.getMatchNode();

			// The first (and may be the only) run can contain text before the match,
			// in this case it is necessary to split the run.
			if (e.getMatchOffset() > 0)
				currentNode = splitRun((Run) currentNode, e.getMatchOffset());

			ArrayList runs = new ArrayList();

			// Find all runs that contain parts of the match string.
			int remainingLength = e.getMatch().group().length();
			while ((remainingLength > 0) && (currentNode != null)
					&& (currentNode.getText().length() <= remainingLength)) {
				runs.add(currentNode);
				remainingLength = remainingLength - currentNode.getText().length();

				// Select the next Run node.
				// Have to loop because there could be other nodes such as BookmarkStart etc.
				do {
					currentNode = currentNode.getNextSibling();
				} while ((currentNode != null) && (currentNode.getNodeType() != NodeType.RUN));
			}

			// Split the last run that contains the match if there is any text left.
			if ((currentNode != null) && (remainingLength > 0)) {
				splitRun((Run) currentNode, remainingLength);
				runs.add(currentNode);
			}

			//// to insert Document
			DocumentBuilder builder = new DocumentBuilder((Document) e.getMatchNode().getDocument());
			builder.moveTo((Run) runs.get(runs.size() - 1));

			builder.insertDocument(doc1, ImportFormatMode.USE_DESTINATION_STYLES);

			for (Run run : (Iterable<Run>) runs)
				run.remove();

			// Signal to the replace engine to do nothing because we have already done all
			// what we wanted.
			return ReplaceAction.SKIP;
		}

		/**
		 * Splits text of the specified run into two runs. Inserts the new run just
		 * after the specified run.
		 */
		private Run splitRun(Run run, int position) throws Exception {
			Run afterRun = (Run) run.deepClone(true);
			afterRun.setText(run.getText().substring(position));
			run.setText(run.getText().substring((0), (0) + (position)));
			run.getParentNode().insertAfter(afterRun, run);
			return afterRun;
		}


	}
}

Could you please help me resolve this issue in the 2025 jar?

@ketanpbh

It sounds like you’re experiencing an issue with the title sequence number when replacing a placeholder in your document after upgrading from Aspose.Words version 2018 to 2025. This can occur due to changes in how the library handles document structures and field updates between versions.

Cause: The issue likely stems from changes in the library’s handling of document elements and field updates, which can affect how sequence numbers are calculated after a placeholder replacement.

Solution: Here are some steps you can take to troubleshoot and resolve the issue:

  1. Ensure Field Updates: Make sure that fields in your document are updated correctly after the replacement. You can do this by calling targetDoc.updateFields(); after performing the replacement. This ensures that all fields, including sequence numbers, are recalculated.

  2. Check Document Structure: Review the structure of your input documents. Changes in how Aspose.Words interprets document elements can lead to differences in output. Ensure that the styles and formatting in your documents are consistent.

  3. Use the Latest Version: If you haven’t already, consider updating to the latest version of Aspose.Words. There may have been bug fixes or improvements that address your issue.

  4. Test with Simplified Code: Create a minimal version of your code that only performs the replacement and updates the fields. This can help isolate the problem and determine if it’s related to your specific implementation or a broader issue with the library.

Here’s a simplified code snippet to illustrate the field update after replacement:

Document targetDoc = new Document("FPS_Template.docx");
Document clauseDoc = new Document("Clause_Cancel_EN.docx");
ReplacingCallback callback = new ReplacingCallback(clauseDoc);
FindReplaceOptions options = new FindReplaceOptions(callback);
options.setMatchCase(true);

targetDoc.getRange().replace("SOWPH_Cancellation", "", options);
targetDoc.updateFields(); // Ensure fields are updated
targetDoc.save("Output_Aspose_25.docx", SaveFormat.DOCX);
  1. Review Release Notes: Check the release notes for version 2025 to see if there are any breaking changes or specific notes regarding placeholder replacements or sequence numbering.

Next Steps: If these steps do not resolve the issue, please provide more details about the specific changes in output, and I can assist you further.

Let me know if this helps!

Hi, @alexey.noskov.

Could you please look into and let me know the reason, thanks in advance.

Best regards,
Anil Chaurasiya

@ketanpbh Please try setting SmartStyleBehavior in ImportFormatOptions. If you modify the code like the following, the numbering will be correct:

ImportFormatOptions opt = new ImportFormatOptions();
opt.setSmartStyleBehavior(true);
builder.insertDocument(doc1, ImportFormatMode.USE_DESTINATION_STYLES, opt);