Hi,
I have a template which is protected and only thing i can do in that doc file is i can fill in the form texts and check boxes.
So i started researching about this and find a way to populate form text boxes using MailMerger, But every field reference is coming as FORMTEXT i am having around 50 text boxes, so when i write code for this every text box is updating with one value and content control is gone(means text box is not visible and only replaced text is visible).
And all these check boxes and text boxes are in tables, can we get table field references and modify form fields in it and add it back to mainDocumentPart?
Please help me out with this, i will attach my code to this post.
private static List<Object> performOnInstance(WordprocessingMLPackage input,
List<Object> contentList,
Map<DataFieldName, String> datamap,
FormTextFieldNames formTextFieldNames) throws Docx4JException {
Body shell = Context.getWmlObjectFactory().createBody();
shell.getContent().addAll(contentList);
Body shellClone = (Body)XmlUtils.deepCopy(shell);
ComplexFieldLocator fl = new ComplexFieldLocator();
new TraversalUtil(shellClone, fl);
log.info("Found " + fl.getStarts().size() + " fields ");
List<FieldRef> fieldRefs = new ArrayList<FieldRef>();
canonicaliseStarts(fl, fieldRefs);
for (FieldRef fr : fieldRefs) {
if ( fr.getFldName().equals("FORMTEXT") ) {
String instr = extractInstr(fr.getInstructions() );
String lang = extractLang(fr.getResultsSlot());
String datafieldName = getDatafieldNameFromInstr(instr);
String val = datamap.get( new DataFieldName(datafieldName));
String gFormat = null; // required only for FORMTEXT conversion
if (StringUtils.isBlank(val)) {
log.warn("Couldn't find value for key: '" + datafieldName + "'");
if (fieldFate.equals(OutputField.REMOVED)) {
// Remove the mergefield from the document
removeSimpleField(fr);
String text = getTextInsideContent(fr.getParent());
// If the parent still contains data, don't delete it
if (StringUtils.isBlank(text)) {
recursiveRemove(shellClone, fr.getParent());
}
}
} else {
// Now format the result
FldSimpleModel fsm = new FldSimpleModel();
try {
fsm.build(instr);
val = FormattingSwitchHelper.applyFormattingSwitch(input, fsm, val, lang);
gFormat = FormattingSwitchHelper.findFirstSwitchValue("\\*", fsm.getFldParameters(), true);
// Solely for potential use in OutputField.AS_FORMTEXT_REGULAR
// We are in fact applying all formatting switches above.
} catch (TransformerException e) {
log.warn("Can't format the field", e);
}
fr.setResult(val);
}
if (fieldFate.equals(OutputField.AS_FORMTEXT_REGULAR)) {
log.debug(gFormat);
// TODO if we're going to use gFormat, setup FSM irrespective of whether we can find key
// TODO: other format instructions
// if (gFormat!=null) {
// if (gFormat.equals("Upper")) {
// gFormat = "UPPERCASE";
// } else if (gFormat.equals("Lower")) {
// gFormat = "LOWERCASE";
// }
// }
// replace instrText
// eg MERGEFIELD CLIENT.ORGANIZATIONSTATE \* Upper \* MERGEFORMAT
// to FORMTEXT
// Do this first, so we can abort without affecting output
List<Object> instructions = fr.getInstructions();
if (instructions.size()!=1) {
log.error("TODO MERGEFIELD field contained complex instruction");
continue;
}
Object o = XmlUtils.unwrap(instructions.get(0));
if (o instanceof Text) {
((Text)o).setValue("FORMTEXT");
} else {
if(log.isErrorEnabled()) {
log.error("TODO: set FORMTEXT in" + o.getClass().getName());
log.error(XmlUtils.marshaltoString(instructions.get(0), true, true));
}
continue;
}
String fieldName = formTextFieldNames.generateName(datafieldName);
log.debug("Field name normalisation: " + datafieldName + " -> " + fieldName);
setFormFieldProperties(fr, fieldName, null);
// remove <w:highlight w:val="lightGray"/>, if present
// (corresponds in Word to clicking Legacy Forms > Form Field Shading)
// so that the result is not printed in grey
R resultR = fr.getResultsSlot();
if (resultR.getRPr()!=null
&& resultR.getRPr().getHighlight()!=null) {
resultR.getRPr().setHighlight(null);
}
} else if (!fieldFate.equals(OutputField.KEEP_MERGEFIELD)) {
// If doing an actual mail merge, the begin-separate run is removed, as is the end run
fr.getParent().getContent().remove(fr.getBeginRun());
fr.getParent().getContent().remove(fr.getEndRun());
}
// System.out.println("AFTER " +XmlUtils.marshaltoString(
// fr.getParent(), true, true));
}
}
return shellClone.getContent();
}