Repeating Merge field in template with hierarchical tables having book mark

Hi There,

I have a template which has hierarchical tables and inside one of the table I have bookmark for repeating merge field.

I am using below code to replace bookmark with tableStart and tableEnd.

public Document replaceTagForBookmarkWithTables(String inputFileName, String tableName, Document doc) throws Exception {

	DocumentBuilder builder = new DocumentBuilder(doc);

	builder.moveToDocumentEnd();
	builder.insertBreak(BreakType.LINE_BREAK);

	// Get All Sections(Pages) in the document
	SectionCollection sections = doc.getSections();
	Section section = null;
	// Iterate over each section.
	for (int sectionIndex = 0; sectionIndex < sections.getCount(); sectionIndex++) {
		section = doc.getSections().get(sectionIndex);
		// Get all tables in the document.
		TableCollection tables = section.getBody().getTables();
		Table table = null;
		// iterate on the tables
		for (int tableIndex = 0; tableIndex < tables.getCount(); tableIndex++) {
			table = tables.get(tableIndex);
			RowCollection rows = table.getRows();
			Row row = null;
			// Iterate on the table rows.
			for (int rowIndex = 0; rowIndex < rows.getCount(); rowIndex++) {
				row = rows.get(rowIndex);
				CellCollection cells = row.getCells();
				Cell cell = null;
				// Iterate on the cells in a row (i.e.,table Columns)
				for (int cellIndex = 0; cellIndex < cells.getCount(); cellIndex++) {
					cell = cells.get(cellIndex);
					TableCollection innerTable = cell.getTables();
					// Get all the bookmarks in the cell range
					BookmarkCollection bookmarks = cell.getRange().getBookmarks();
					if (bookmarks != null && bookmarks.getCount() > 0) {
						// Get the first bookmark and insert the new merge field in the first cell and
						// the last cell
						// and remove the bookmark from the document.
						Bookmark bookmark = bookmarks.get(0);
						BookmarkStart bms = cell.getRange().getBookmarks().get(0).getBookmarkStart();
						BookmarkEnd bme = cell.getRange().getBookmarks().get(0).getBookmarkEnd();

						CompositeNode bmsParent = bms.getParentNode().getParentNode();
						CompositeNode bmeParent = bme.getParentNode().getParentNode();


						if (bookmark != null) {
							String bookmarkName = bookmark.getName();
							tableName = bookmarkName;
							// Get the cursor position to the beginning of the first cell and insert the new
							// merge field.
							builder.moveToCell(tableIndex, rowIndex, cellIndex, 0);
							builder.insertField("MERGEFIELD TableStart:" + tableName + " \\* MERGEFORMAT",
									"«TableStart:" + tableName + "»");

							if (bmsParent != null && bmeParent != null && bmsParent == bmeParent) {
								builder.moveToCell(tableIndex, rowIndex, cellIndex, -1);
							}else {
								builder.moveToCell(tableIndex, rowIndex, cells.getCount() - 1, -1);
							}
							builder.insertField("MERGEFIELD TableEnd:" + tableName + " \\* MERGEFORMAT", "+ tableName + ");
							bookmark.remove();
						}
					}
				}
			}
		}
	}
	return doc;
}

I am getting below exception for my template

java.lang.IllegalStateException: Mail merge region ‘bBookMark’ is badly formed. TableStart and TableEnd should be in the same section, same table row or same table cell.

HTML Template contains structure similar to:

<html>
<head>
</head>
<body lang=EN-GB style='tab-interval:36.0pt;word-wrap:break-word'>
    <div class=WordSection1>
        <table>
            <tr>
                <td>
                    <table>
                        <tr>
                            <td>
                                <table>
                                    <tr>
                                        <td>This is test template format for testing repeating merge field</td>
                                    </tr>
                                    <tr>
                                        <td>
                                            <table align='center'>
                                                <tr>
                                                    <td>
                                                        <p class=MsoNormal>
                                                            <a name=bBookMark></a>
                                                            <!--[if supportFields]><span
                                                            style='mso-bookmark:bBookMark'></span><span style='mso-element:field-begin'></span><span
                                                            style='mso-bookmark:bBookMark'><span style='mso-fareast-font-family:
                                                            "Times New Roman"'><span style='mso-spacerun:yes'>&nbsp;</span>MERGEFIELD<span
                                                            style='mso-spacerun:yes'>&nbsp; </span>firstName<span
                                                            style='mso-spacerun:yes'>&nbsp; </span>\* MERGEFORMAT <span
                                                            style='mso-element:field-separator'></span></span></span><![endif]-->
                                                            <span style='mso-bookmark:bBookMark'>
                                                                <span style='mso-fareast-font-family:
            "Times New Roman"'><span style='mso-no-proof:yes'>&laquo;firstName&raquo;</span></span>
                                                            </span>
                                                            <!--[if supportFields]><span
                                                            style='mso-bookmark:bBookMark'></span><span style='mso-element:field-end'></span><![endif]-->
                                                            <span style='mso-bookmark:bBookMark'>
                                                                <span style='mso-fareast-font-family:
            "Times New Roman"'><o:p></o:p></span>
                                                            </span>
                                                        </p>
                                                    </td>
                                                    <span style='mso-bookmark:bBookMark'></span>
                                                    <td width=24 valign=top style='width:18.0pt;border:solid windowtext 1.0pt;
            border-left:none;mso-border-left-alt:solid windowtext .5pt;mso-border-alt:
            solid windowtext .5pt;padding:0mm 5.4pt 0mm 5.4pt'>
                                                        <p class=MsoNormal>
                                                            <!--[if supportFields]><span style='mso-fareast-font-family:
                                                            "Times New Roman"'><span style='mso-element:field-begin'></span><span
                                                            style='mso-spacerun:yes'>&nbsp;</span>MERGEFIELD<span
                                                            style='mso-spacerun:yes'>&nbsp; </span>lastName<span
                                                            style='mso-spacerun:yes'>&nbsp; </span>\* MERGEFORMAT <span
                                                            style='mso-element:field-separator'></span></span><![endif]-->
                                                            <span style='mso-fareast-font-family:"Times New Roman"'>
                                                                <span style='mso-no-proof:yes'>&laquo;lastName&raquo;</span>
                                                            </span>
                                                            <!--[if supportFields]><span
                                                            style='mso-fareast-font-family:"Times New Roman"'><span
                                                            style='mso-element:field-end'></span></span><![endif]-->
                                                            <span style='mso-fareast-font-family:"Times New Roman"'><o:p></o:p></span>
                                                        </p>
                                                    </td>
                                                </tr>
                                                <tr>
                                                    <td>
                                                        <span style='mso-bookmark:bBookMark'></span>
                                                        <p class=MsoNormal>
                                                            <span style='mso-bookmark:bBookMark'>
                                                                <span style='mso-fareast-font-family:"Times New Roman"'><o:p>&nbsp;</o:p></span>
                                                            </span>
                                                        </p>
                                                    </td>
                                                    <span style='mso-bookmark:bBookMark'></span>
                                                    <td>
                                                        <p class=MsoNormal><span style='mso-fareast-font-family:"Times New Roman"'><o:p>&nbsp;</o:p></span></p>
                                                    </td>
                                                </tr>
                                            </table>
                                            <span style='mso-bookmark:bBookMark'></span>
                                        </td>
                                        <span style='mso-bookmark:bBookMark'></span>
                                    </tr>
                                </table>
                            </td>
                            <td style='padding:.75pt .75pt .75pt .75pt'></td>
                        </tr>
                        <tr style='mso-yfti-irow:1;mso-yfti-lastrow:yes'>
                            <td style='padding:.75pt .75pt .75pt .75pt'>
                                <table class=MsoNormalTable border=1 cellpadding=0 style='mso-cellspacing:
         1.5pt;border:solid windowtext 1.0pt;mso-border-alt:solid windowtext .5pt;
         mso-yfti-tbllook:1184;mso-border-insideh:.5pt solid windowtext;mso-border-insidev:
         .5pt solid windowtext'>
                                    <tr style='mso-yfti-irow:0;mso-yfti-firstrow:yes;mso-yfti-lastrow:yes'>
                                        <td style='border:solid windowtext 1.0pt;mso-border-alt:solid windowtext .5pt;
          padding:.75pt .75pt .75pt .75pt'>
                                            <p class=MsoNormal><span style='mso-fareast-font-family:"Times New Roman"'>Some Text at the bottom<o:p></o:p></span></p>
                                        </td>
                                    </tr>
                                </table>
                            </td>
                            <td style='padding:.75pt .75pt .75pt .75pt'></td>
                        </tr>
                    </table>
                </td>
            </tr>
        </table>
        <p class=MsoNormal><span style='mso-fareast-font-family:"Times New Roman"'><o:p>&nbsp;</o:p></span></p>
    </div>
</body>
</html>

@vapanchamukhi After running your code table start and table end merge fields are inserted into different rows and even in different tables:

If you would like to wrap whole nested table into table start and table end merge fields, it is required to insert an empty paragraph before the nested table to make it possible to insert a merge field before the table. Please modify your code like this:

// .............
cell = cells.get(cellIndex);
if(cell.getFirstChild().getNodeType() == NodeType.TABLE)
    cell.prependChild(new Paragraph(doc));
// .............

In this case the final document structure will look like this:

Hi Alexey,

Thanks for your suggestion. This solution partially worked. Which means, outside table is repeating instead of inner table around which bookmark is added. I just want to repeat bookmarked section.

Current output looks like:

<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<meta http-equiv="Content-Style-Type" content="text/css" />
	<meta name="generator" content="Aspose.Words for Java 22.9.0" />
	<title>
	</title>
</head>
<body style="font-family:'Times New Roman'; font-size:12pt">
	<div>
		<table cellspacing="2" cellpadding="0" style="border-spacing:1.5pt">
			<tr>
				<td style="padding:0.75pt; vertical-align:middle">
					<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
						<span style="-aw-import:ignore">&#xa0;</span>
					</p>
					<table cellspacing="2" cellpadding="0" style="border-spacing:1.5pt">
						<tr>
							<td style="padding:0.75pt; vertical-align:middle">
								<table cellspacing="2" cellpadding="0" style="border-spacing:1.5pt">
									<tr>
										<td style="padding:0.75pt; vertical-align:middle">
											<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
												<span>This is test template format for testing repeating merge field</span>
											</p>
										</td>
									</tr>
									<tr>
										<td style="padding:0.75pt; vertical-align:middle">
											<div style="text-align:center">
												<table cellspacing="2" cellpadding="0" style="margin-right:auto; margin-left:auto; border-spacing:1.5pt">
													<tr>
														<td style="padding:0.75pt; vertical-align:middle">
															<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
																<span>First Name 1</span>
															</p>
														</td>
														<td style="width:18pt; border-top-style:solid; border-top-width:1pt; border-right-style:solid; border-right-width:1pt; border-bottom-style:solid; border-bottom-width:1pt; padding-right:5.4pt; padding-left:5.4pt; vertical-align:top">
															<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
																<span>Last Name 1</span>
															</p>
														</td>
													</tr>
													<tr>
														<td style="padding:0.75pt; vertical-align:middle">
															<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
																<span>&#xa0;</span>
															</p>
														</td>
														<td style="padding:0.75pt; vertical-align:middle">
															<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
																<span>&#xa0;</span>
															</p>
														</td>
													</tr>
												</table>
											</div>
											<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
											</p>
										</td>
									</tr>
								</table>
								<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
								</p>
							</td>
							<td style="padding:0.75pt; vertical-align:middle">
								<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
									<span style="-aw-import:ignore">&#xa0;</span>
								</p>
							</td>
						</tr>
						<tr>
							<td style="padding:0.75pt; vertical-align:middle">
								<table cellspacing="2" cellpadding="0" style="border:1pt solid #000000; border-spacing:1.5pt">
									<tr>
										<td style="border-style:solid; border-width:1pt; padding:0.75pt; vertical-align:middle">
											<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
												<span>Some Text at the bottom</span>
											</p>
										</td>
									</tr>
								</table>
								<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
								</p>
							</td>
							<td style="padding:0.75pt; vertical-align:middle">
								<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
									<span style="-aw-import:ignore">&#xa0;</span>
								</p>
							</td>
						</tr>
					</table>
					<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
						<span style="-aw-import:ignore">&#xa0;</span>
					</p>
					<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
						<span style="-aw-import:ignore">&#xa0;</span>
					</p>
					<table cellspacing="2" cellpadding="0" style="border-spacing:1.5pt">
						<tr>
							<td style="padding:0.75pt; vertical-align:middle">
								<table cellspacing="2" cellpadding="0" style="border-spacing:1.5pt">
									<tr>
										<td style="padding:0.75pt; vertical-align:middle">
											<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
												<span>This is test template format for testing repeating merge field</span>
											</p>
										</td>
									</tr>
									<tr>
										<td style="padding:0.75pt; vertical-align:middle">
											<div style="text-align:center">
												<table cellspacing="2" cellpadding="0" style="margin-right:auto; margin-left:auto; border-spacing:1.5pt">
													<tr>
														<td style="padding:0.75pt; vertical-align:middle">
															<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
																<span>First Name 2</span>
															</p>
														</td>
														<td style="width:18pt; border-top-style:solid; border-top-width:1pt; border-right-style:solid; border-right-width:1pt; border-bottom-style:solid; border-bottom-width:1pt; padding-right:5.4pt; padding-left:5.4pt; vertical-align:top">
															<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
																<span>Last Name 2</span>
															</p>
														</td>
													</tr>
													<tr>
														<td style="padding:0.75pt; vertical-align:middle">
															<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
																<span>&#xa0;</span>
															</p>
														</td>
														<td style="padding:0.75pt; vertical-align:middle">
															<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
																<span>&#xa0;</span>
															</p>
														</td>
													</tr>
												</table>
											</div>
											<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
											</p>
										</td>
									</tr>
								</table>
								<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
								</p>
							</td>
							<td style="padding:0.75pt; vertical-align:middle">
								<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
									<span style="-aw-import:ignore">&#xa0;</span>
								</p>
							</td>
						</tr>
						<tr>
							<td style="padding:0.75pt; vertical-align:middle">
								<table cellspacing="2" cellpadding="0" style="border:1pt solid #000000; border-spacing:1.5pt">
									<tr>
										<td style="border-style:solid; border-width:1pt; padding:0.75pt; vertical-align:middle">
											<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
												<span>Some Text at the bottom</span>
											</p>
										</td>
									</tr>
								</table>
								<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
								</p>
							</td>
							<td style="padding:0.75pt; vertical-align:middle">
								<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
									<span style="-aw-import:ignore">&#xa0;</span>
								</p>
							</td>
						</tr>
					</table>
					<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
					</p>
				</td>
			</tr>
		</table>
		<p style="margin-top:12pt; margin-bottom:12pt">
			<span>&#xa0;</span><br /><span style="-aw-import:ignore">&#xa0;</span>
		</p>
	</div>
</body>

Instead I wanted it to be as below:

<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<meta http-equiv="Content-Style-Type" content="text/css" />
	<meta name="generator" content="Aspose.Words for Java 22.9.0" />
	<title>
	</title>
</head>
<body style="font-family:'Times New Roman'; font-size:12pt">
	<div>
		<table cellspacing="2" cellpadding="0" style="border-spacing:1.5pt">
			<tr>
				<td style="padding:0.75pt; vertical-align:middle">
					<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
						<span style="-aw-import:ignore">&#xa0;</span>
					</p>
					<table cellspacing="2" cellpadding="0" style="border-spacing:1.5pt">
						<tr>
							<td style="padding:0.75pt; vertical-align:middle">
								<table cellspacing="2" cellpadding="0" style="border-spacing:1.5pt">
									<tr>
										<td style="padding:0.75pt; vertical-align:middle">
											<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
												<span>This is test template format for testing repeating merge field</span>
											</p>
										</td>
									</tr>
									<tr>
										<td style="padding:0.75pt; vertical-align:middle">
											<div style="text-align:center">
												<table cellspacing="2" cellpadding="0" style="margin-right:auto; margin-left:auto; border-spacing:1.5pt">
													<tr>
														<td style="padding:0.75pt; vertical-align:middle">
															<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
																<span>First Name 1</span>
															</p>
														</td>
														<td style="width:18pt; border-top-style:solid; border-top-width:1pt; border-right-style:solid; border-right-width:1pt; border-bottom-style:solid; border-bottom-width:1pt; padding-right:5.4pt; padding-left:5.4pt; vertical-align:top">
															<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
																<span>Last Name 1</span>
															</p>
														</td>
													</tr>
													<tr>
														<td style="padding:0.75pt; vertical-align:middle">
															<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
																<span>First Name 2</span>
															</p>
														</td>
														<td style="width:18pt; border-top-style:solid; border-top-width:1pt; border-right-style:solid; border-right-width:1pt; border-bottom-style:solid; border-bottom-width:1pt; padding-right:5.4pt; padding-left:5.4pt; vertical-align:top">
															<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
																<span>Last Name 2</span>
															</p>
														</td>
													</tr>
													<tr>
														<td style="padding:0.75pt; vertical-align:middle">
															<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
																<span>&#xa0;</span>
															</p>
														</td>
														<td style="padding:0.75pt; vertical-align:middle">
															<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
																<span>&#xa0;</span>
															</p>
														</td>
													</tr>
												</table>
											</div>
											<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
											</p>
										</td>
									</tr>
								</table>
								<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
								</p>
							</td>
							<td style="padding:0.75pt; vertical-align:middle">
								<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
									<span style="-aw-import:ignore">&#xa0;</span>
								</p>
							</td>
						</tr>
						<tr>
							<td style="padding:0.75pt; vertical-align:middle">
								<table cellspacing="2" cellpadding="0" style="border:1pt solid #000000; border-spacing:1.5pt">
									<tr>
										<td style="border-style:solid; border-width:1pt; padding:0.75pt; vertical-align:middle">
											<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
												<span>Some Text at the bottom</span>
											</p>
										</td>
									</tr>
								</table>
								<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
								</p>
							</td>
							<td style="padding:0.75pt; vertical-align:middle">
								<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
									<span style="-aw-import:ignore">&#xa0;</span>
								</p>
							</td>
						</tr>
					</table>
					<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
						<span style="-aw-import:ignore">&#xa0;</span>
					</p>
					<p style="margin-top:0pt; margin-bottom:0pt; font-size:12pt">
					</p>
				</td>
			</tr>
		</table>
		<p style="margin-top:12pt; margin-bottom:12pt">
			<span>&#xa0;</span><br /><span style="-aw-import:ignore">&#xa0;</span>
		</p>
	</div>
</body>
</html>

@vapanchamukhi Please try using the following code to get the desired result:

Document doc = new Document("C:\\Temp\\in.html");
DocumentBuilder builder = new DocumentBuilder(doc);
    
String tableName = "bBookMark";
// Get ta table where the bookmark is placed.
Table table = (Table) doc.getRange().getBookmarks().get(tableName).getBookmarkStart().getAncestor(NodeType.TABLE);
if(table!=null)
{
    // Make sure there is paragraph before and after the table.
    if(table.getPreviousSibling()==null || table.getPreviousSibling().getNodeType()!=NodeType.PARAGRAPH)
        table.getParentNode().insertBefore(new Paragraph(doc), table);
    if(table.getNextSibling()==null || table.getNextSibling().getNodeType()!=NodeType.PARAGRAPH)
        table.getParentNode().insertAfter(new Paragraph(doc), table);
    
    // Insert MERGEFIELD TableStart before the table.
    builder.moveTo(table.getPreviousSibling());
    builder.insertField("MERGEFIELD TableStart:" + tableName + " \\* MERGEFORMAT",
            "«TableStart:" + tableName + "»");
    // Insert MERGEFIELD TableEnd after the table.
    builder.moveTo(table.getNextSibling());
    builder.insertField("MERGEFIELD TableEnd:" + tableName + " \\* MERGEFORMAT",
            "«TableEnd:" + tableName + "»");
}
        
// Execute test mail merge.
DataTable dt = new DataTable(tableName);
dt.getColumns().add("dummy");
for(int i=0; i<5; i++)
    dt.getRows().add("dummy data");
    
doc.getMailMerge().setCleanupOptions(MailMergeCleanupOptions.REMOVE_EMPTY_PARAGRAPHS);
doc.getMailMerge().executeWithRegions(dt);
        
doc.save("C:\\Temp\\out.docx");

Here is the output document: out.docx (8.7 KB)

Hi Alexey,

Thanks for resolving this problem. Its working. But between two lines there is extra space coming. How can this be removed?

Regards,
Vidyabhushan

@vapanchamukhi Please try specifying the following cleanup option before executing mail merge:

doc.getMailMerge().setCleanupOptions(MailMergeCleanupOptions.REMOVE_EMPTY_PARAGRAPHS);