Bookmarks with Nested Fields | Preserve Fields during Bookmark Text Replacement using Java

Hello,

I Have a boomark defined like this:

    bookmarkValue{ \bookmarkName }

then in the .docx I have various references defined like this:

    {ref bookmarkName \* CHARFORMAT}

I want set bookmarkValue but without loose the bookmark itself.

Now if I do:

bookmarks.get(“bookMarkName”).setText(“foo”);

the result is “foo” written where is the bookmark but the bookmark is lost becomed a plain text.

I need the bookmark becomes:

foo{ \bookMarkName }

thanks

@akumpum,

Please compress the following resources into ZIP format and attach the .zip file here for testing:

  • A simplified source Word document containing the Bookmark
  • Aspose.Words generated output document showing the undesired behavior
  • Your expected Word file showing the desired output. You can create this file manually by using MS Word.

As soon as you get these pieces of information ready, we will then start investigation into your particular issue and provide you more information.

aspose_evaluating.zip (224.0 KB)

Thanks for your reply

I’m evaluating a docx-API for my Company and I need to know If, using Aspose, there’s the possibility to manipulate our docx as described in the issue.

I attached a zip with a readme, source, desired and output docs.

@akumpum,

The problematic text contents { \interno } and { \bancanome } are actually parts of target Bookmarks. It is expected behavior that when you set text of such bookmarks, these fields of type None got removed. But, you can take out these fields from inside Bookmarks and then set Text. Please check the following code:

Document doc = new Document("C:\\Temp\\aspose_evaluating\\02. doc_source.docx");

Bookmark bookmark_bancaNome = doc.getRange().getBookmarks().get("bancanome");
Bookmark bookmark_interno = doc.getRange().getBookmarks().get("interno");

ArrayList fields = getBookmarkFields(bookmark_bancaNome, 0);
if (fields.size() > 0) {
    for (Field field : (Iterable<Field>) fields) {
        insertFieldAfter(field, bookmark_bancaNome.getBookmarkEnd());
    }
}

fields = getBookmarkFields(bookmark_interno, 0);
if (fields.size() > 0) {
    for (Field field : (Iterable<Field>) fields) {
        insertFieldAfter(field, bookmark_interno.getBookmarkEnd());
    }
}

bookmark_interno.setText("123-456789");
bookmark_bancaNome.setText("Rome");

doc.updateFields();

doc.save("C:\\Temp\\aspose_evaluating\\awjava-21.5.docx");

public static ArrayList getBookmarkFields(Bookmark bookmark, int fieldType) throws Exception {
    ArrayList listOfFields = new ArrayList();

    Node currentNode = bookmark.getBookmarkStart();
    while (currentNode != null && currentNode != bookmark.getBookmarkEnd()) {
        if (currentNode.getNodeType() == NodeType.FIELD_START) {
            FieldStart start = (FieldStart) currentNode;
            if (start.getFieldType() == fieldType)
                listOfFields.add(start.getField());
        }

        Node nextNode = currentNode.nextPreOrder(currentNode.getDocument());
        currentNode = nextNode;
    }

    return listOfFields;
}

public static void insertFieldAfter(Field field, Node referenceNode) {
    Node currentNode = field.getEnd();
    while (currentNode != null) {
        if (currentNode == field.getStart())
        {
            referenceNode.getParentNode().insertAfter(currentNode, referenceNode);
            break;
        }

        Node previousNode = currentNode.previousPreOrder(currentNode.getDocument());
        referenceNode.getParentNode().insertAfter(currentNode, referenceNode);
        currentNode = previousNode;
    }
}

@ awais.hafeez

Thanks for your accurate reply, I will try your code but first what about this solution ?

	public void replaceVariabiliInGriglia (List<Variabile> variabili) throws Exception {
		    		
		NodeCollection<Table> tables = 
              doc.getChildNodes(NodeType.TABLE, true);
		
		int numTables = tables.getCount();
		
		Table griglia = (Table)tables.get(0);
		
		for (Row row : griglia.getRows()) {
			
			 Cell cell = row.getCells().get(1);
		
			 if (cell != null) {
				 
				 for (Variabile variabile : variabili) {
					 
					 String cellText = cell.getText();
					 
					 String varPlaceHolder = "<" + variabile.getName() + ">";
					 
					 if (cellText.contains(varPlaceHolder)) {

						 System.out.println("varPlaceHolder: " + varPlaceHolder);

						 cell.getRange().replace(varPlaceHolder, 

                                             variabile.getContent().toString());	 

					 } //if cell contains varPlaceHolder
					 	
				 } //for variabili
				 
			 }  //if cell != null

		} //for rows
		
		this.doc.updateFields();
		
	} //replaceVariablesInGriglia

@akumpum,

Yes, this should work. There can be multiple ways to meet this requirement; e.g. if variable names in Word document are unique then you can simply use the following statements:

Document doc = new Document("C:\\Temp\\aspose_evaluating\\02. doc_source.docx");

doc.getRange().replace("<phoneNum>", "123-456789");
doc.getRange().replace("<bankName>", "Rome");

doc.updateFields();

doc.save("C:\\Temp\\aspose_evaluating\\awjava-21.5.docx");