Empty paragraph after merge even when REMOVE_EMPTY_PARAGRAPHS is set

Hi,

I was reading the docs about mail merge cleanup at https://docs.aspose.com/words/net/clean-up-before-or-during-mail-merge/, but it seems I cannot get the REMOVE_EMPTY_PARAGRAPHS option to work.

I have attached a ZIP file which contains two DOC files, personale_it.doc is the template and custom_test.doc is the result.

Has you see, the template has regions which contain paragraphs, specifically the gray ones; after the merge if the field titolo_sezione is empty the gray paragraph is still there, while I’d like it to be removed.

The mail merge is performed with the following code, which uses an XML InputStream:

private static void merge(Document document, InputStream xmlStream, boolean withRegions) throws Exception {
	// imposto trigger per merge immagini e HTML, e abilito sintassi Mustache
	com.aspose.words.MailMerge mm = document.getMailMerge();
	mm.setFieldMergingCallback(new ImageMerge());
	mm.setTrimWhitespaces(true);

	// creo il dataset
	DataSet dataSet = new DataSet();
	dataSet.readXml(xmlStream);

	// eventuale merge delle regioni
	if (withRegions) {
		mm.setMergeDuplicateRegions(true);

		// imposto pulizia campi non usati
		mm.setCleanupOptions(
			// rimozione regioni non compilate
			MailMergeCleanupOptions.REMOVE_UNUSED_REGIONS
			// rimozione righe di tabella vuote
			| MailMergeCleanupOptions.REMOVE_EMPTY_TABLE_ROWS
		);

		// eseguo merge
		mm.executeWithRegions(dataSet);
	}

	// imposto pulizia campi non usati
	mm.setCleanupOptions(
		// rimozione campi non compilati
		MailMergeCleanupOptions.REMOVE_UNUSED_FIELDS
		// rimozione campi innestati
		| MailMergeCleanupOptions.REMOVE_CONTAINING_FIELDS
		// rimozione paragrafi vuoti
		| MailMergeCleanupOptions.REMOVE_EMPTY_PARAGRAPHS
	);

	// eseguo merge
	mm.execute(dataSet.getTables().get(0));
}

What exactly am I doing wrong?

Thanks.

mail_merge_cleanup.zip (70.6 KB)

@mtassinari,

Thanks for your inquiry. Please ZIP and attach your XML data source here for testing. We will investigate the issue on our side and provide you more information.

Here it is!

personale.zip (3.1 KB)

You might also need this:

public class ImageMerge implements IFieldMergingCallback {
	/**
	 * Trigger per image field merging, gestisce immagini come path sul disco.
	 *
	 * @param ifma
	 * @throws Exception
	 */
	public void imageFieldMerging(ImageFieldMergingArgs ifma) throws Exception {
		try {
			// immagine richiesta
			Object field = ifma.getFieldValue();
			String path = "";

			// array di byte come path
			if (field instanceof byte[]) {
				path = new String((byte[]) field, StandardCharsets.UTF_8);
			}
			// path come stringa semplice
			else {
				path = field.toString();
			}

			// se non è valido, non proseguo
			if (!Strings.isValid(path)) {
				ifma.setImage(null);
				return;
			}
			// se non esiste
			else if (!Files.exists(path)) {
				// assumo come path relativo alla cartella di installazione
				path = Util.getInstallFolder() + path;

				// se non esiste
				if (!Files.exists(path)) {
					// non è valido
					path = "";
				}
			}

			// dimensioni specificate nel documento (eventualmente non presenti)
			double width = ifma.getImageWidth().getValue();
			double height = ifma.getImageHeight().getValue();

			// se le dimensioni non sono già specificate
			if (width < 0 && height < 0) {
				DocumentBuilder builder = new DocumentBuilder(ifma.getDocument());
				builder.moveToMergeField(ifma.getDocumentFieldName(), false, false);

				// se si trova in una cella di una tabella
				Cell cell = (Cell) builder.getCurrentParagraph().getAncestor(NodeType.CELL);
				if (cell != null) {
					CellFormat format = cell.getCellFormat();

					format.setLeftPadding(0.0);
					format.setRightPadding(0.0);
					format.setTopPadding(0.0);
					format.setBottomPadding(0.0);
					format.setWrapText(false);
					format.setFitText(true);

					// uso dimensioni cella
					width = format.getWidth();
					height = cell.getParentRow().getRowFormat().getHeight();
				}

				// se si trova in un textbox
				Shape shape = (Shape) builder.getCurrentParagraph().getAncestor(NodeType.SHAPE);
				if (shape != null && shape.getShapeType() == ShapeType.TEXT_BOX) {
					TextBox tb = shape.getTextBox();

					tb.setInternalMarginBottom(0.0);
					tb.setInternalMarginTop(0.0);
					tb.setInternalMarginLeft(0.0);
					tb.setInternalMarginRight(0.0);

					// uso dimensioni textbox
					width = shape.getWidth();
					height = shape.getHeight();
				}
			}

			// se sono specificate misure massime
			if (width > 0 && height > 0) {
				// carico immagine
				BufferedImage img = ImageIO.read(new File(path));

				// ricavo fattore di scala
				int imgw = img.getWidth();
				int imgh = img.getHeight();

				// distruggo immagine
				img = null;

				// calcolo fattore di scalatura
				double scale = Math.max(imgw / width, imgh / height);

				// inserisco l'immagine specificando le dimensioni
				width = imgw / scale;
				height = imgh / scale;
			}

			// immagine come path sul disco
			ifma.setImageFileName(path);

			// imposto le dimensioni
			ifma.getImageWidth().setValue(width);
			ifma.getImageHeight().setValue(height);
		}
		// se qualcosa va male
		catch (Exception e) {
			// in modalità debug
			if (Util.DEBUG) {
				// riporta errore
				throw Util.error("Errore durante il caricamento di un'immagine", e);
			}
			// altrimenti
			else {
				// setta immagine a null
				ifma.setImage(null);
			}
		}
	}

	/**
	 * Trigger per field merging, gestisce HTML.
	 *
	 * @param fma
	 * @throws Exception
	 */
	public void fieldMerging(FieldMergingArgs fma) throws Exception {
		// Se il nome del campo inizia con "html_" assumo sia formattato HTML
		if (fma.getDocumentFieldName().startsWith("html_") && fma.getFieldValue() != null) {
			// effettuo inserimento tramite un DocumentBuilder
			com.aspose.words.DocumentBuilder builder = new com.aspose.words.DocumentBuilder(fma.getDocument());
			builder.moveToMergeField(fma.getDocumentFieldName());
			builder.insertHtml(fma.getFieldValue().toString(), true);

			// e annullo il testo effettivamente già inserito
			fma.setText("");
			return;
		}

		// se il valore è una stringa
		if (fma.getFieldValue() instanceof String) {
			// la estraggo
			String value = (String) fma.getFieldValue();
			Boolean checked = false;

			// ne verifico il valore
			switch (value) {
				// se è "true" o false"
				case "true":
				case "TRUE":
					checked = true;
					// fallthrough
				case "false":
				case "FALSE":
					// inserisco un checkbox tramite DocumentBuilder
					DocumentBuilder builder = new DocumentBuilder(fma.getDocument());
					builder.moveToMergeField(fma.getFieldName());
					builder.insertCheckBox(
						fma.getFieldName() + fma.getRecordIndex(),
						checked,
						0
					);

					// e annullo il testo effettivamente già inserito
					fma.setText("");
					break;

				// altrimenti merge normale
				default: break;
			}
		}
	}
}

@mtassinari,

Thanks for sharing the detail. Please use MailMergeCleanupOptions as shown below to get the desired output. Please use MailMergeCleanupOptions.REMOVE_EMPTY_PARAGRAPHS to remove empty paragraphs.

DataSet dataSet = new DataSet();
dataSet.readXml(MyDir + "personale.xml");

// eventuale merge delle regioni
if (true) {
    mm.setMergeDuplicateRegions(true);

    // imposto pulizia campi non usati
    mm.setCleanupOptions(
            // rimozione regioni non compilate
            MailMergeCleanupOptions.REMOVE_UNUSED_REGIONS
                    // rimozione righe di tabella vuote
                    | MailMergeCleanupOptions.REMOVE_EMPTY_TABLE_ROWS
                    | MailMergeCleanupOptions.REMOVE_EMPTY_PARAGRAPHS
    );

    // eseguo merge
    mm.executeWithRegions(dataSet);
}

That does not seem to work, see the attached output created using your suggestion.

As you can see, between the first two red lines, there should be an empty one, which now is missing; however the gray empty line is correctly gone.

I wish paragraphs to be removed ONLY if they’re made of a merge field which has not been merged; is this possible at all? Should I fix my template somehow?

custom_test.zip (61.3 KB)

@mtassinari,

Thanks for your inquiry. Please insert the empty paragraph before TableStart:XXX field as shown in attached image to get the desired output. empty paragraph.png (18.1 KB)