I am trying to insert an RTF document in place of a mustache tag using the IFieldMergingCallback.
No matter what I do, I cannot get it to replace the {{x}} tag in the document. The result is always is placed after the paragraph.
I have a RTF document which looks like this (omitting the full RTF):
{\rtf1\ansi … {{#foreach row}}The house is {{x}}.{{/foreach row} }
I am inserting another RTF string (which i convert to a document) like this:
{\rtf1\ansi … ‘RED’ … }
Using the callback (either text or RTF format) I get:
The house is .
RED <— inserted document on next line
Without the callback (using Text format i get the correct value / Rtf Format puts the raw RTF string in place) I get:
The house is RED.
I am using almost exactly the example(s) from this thread Insert RTF text into a table using ExecuteWithRegions - including the insertDocument and MergeFieldCallbacks code.
Here is the test case I am running against (both snippets are converted to documents):
@Test
// @Ignore
public void should_merge_rtf_fields_into_rtf() throws Exception
{
final String source = ""
+ "{\rtf1\ansi\ansicpg1252\cocoartf1265\cocoasubrtf200"
+ "{\fonttbl\f0\fswiss\fcharset0 Helvetica;}"
+ "{\colortbl;\red255\green255\blue255;\red0\green31\blue103;\red102\green0\blue141;}"
+ "\margl1440\margr1440\vieww10800\viewh8400\viewkind0"
+ "\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural"
+ "\f0\fs24 \cf0 \{\{#foreach row\}\}The "
+ "\i\fs28 \cf2 \ul \ulc2 house"
+ "\i0\fs24 \cf0 \ulnone is "
+ "\b \cf3 \{\{\ul x\ulnone \}\}"
+ "\b0 \cf0 .\{\{/foreach row\}\}}";
final String snippet = ""
+ "{\rtf1\ansi\ansicpg1252\cocoartf1265\cocoasubrtf200"
+ "{\fonttbl\f0\fswiss\fcharset0 Helvetica;}"
+ "{\colortbl;\red255\green255\blue255;\red110\green5\blue0;}"
+ "\margl1440\margr1440\vieww10800\viewh8400\viewkind0"
+ "\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural"
+ "\f0\b\fs24 \cf0 Big and \cf2 \ul \ulc2 red}";
// Merge field (RTF snippet)
final Map<String, Object> customData = Maps.newHashMap();
customData.put("x", snippet);
final Dataset data = new Dataset(customData);
// Perform merge
final String actual = this.processor.merge(source, data, TextFormat.TXT);
assertThat(actual, equalTo(""
+ "The house is Big and Red."));
}
Here is my insertDocument() method:
static void insertDocument(Node target, final Document source) throws Exception
{
// Make sure the target is either a paragraph or table.
final int nodeType = target.getNodeType();
if (nodeType != NodeType.PARAGRAPH & nodeType != NodeType.TABLE)
{
throw new IllegalArgumentException("The destination should be a paragraph or table.");
}
// We will be inserting into the parent of the destination paragraph.
final CompositeNode<?> parent = target.getParentNode();
// This object will be translating styles and lists during the import.
final NodeImporter importer = new NodeImporter(
source,
target.getDocument(),
ImportFormatMode.USE_DESTINATION_STYLES);
for (final Section section : source.getSections())
{
// Loop through all block level nodes (paragraphs and tables) in the
// body of the section.
for (final Node sourceNode : (Iterable)section.getBody())
{
// Skip the node if is last empty paragraph in a section.
if (sourceNode.getNodeType() == NodeType.PARAGRAPH)
{
final Paragraph para = (Paragraph)sourceNode;
if (para.isEndOfSection() && !para.hasChildNodes())
{
continue;
}
}
// Clone of the node, suitable for insertion into
// the destination document.
final Node newNode = importer.importNode(sourceNode, true);
// Insert the new node after the current target
parent.insertAfter(newNode, target);
target = newNode;
}
}
}
Here is my callback:
private final class MergedFieldCallback implements IFieldMergingCallback
{
@Override
public void fieldMerging(final FieldMergingArgs args) throws Exception
{
final String fieldName = args.getDocumentFieldName();
final Object fieldValue = args.getFieldValue();
final Document document = args.getDocument();
final DocumentBuilder builder = new DocumentBuilder(document);
// Move to merge field and insert into paragraph
if (builder.moveToMergeField(fieldName))
{
final Document snippet = createDocument(fieldValue.toString());
final Paragraph paragraph = builder.getCurrentParagraph();
insertDocument(paragraph, snippet);
// The paragraph that contained the field might be empty
// now and you probably want to delete it.
if (!paragraph.hasChildNodes())
{
paragraph.remove();
}
// Set text of mergefield to nothing.
args.setText(null);
}
}
@Override
public void imageFieldMerging(final ImageFieldMergingArgs args) throws Exception
{
throw new UnsupportedOperationException();
}
}