org.docx4j.model.datastorage.migration.FromMergeFields Maven / Gradle / Ivy
package org.docx4j.model.datastorage.migration;
import org.docx4j.TraversalUtil;
import org.docx4j.XmlUtils;
import org.docx4j.model.fields.ComplexFieldLocator;
import org.docx4j.model.fields.FieldRef;
import org.docx4j.model.fields.FieldsPreprocessor;
import org.docx4j.openpackaging.io.SaveToZipFile;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.wml.ContentAccessor;
import org.docx4j.wml.P;
import org.docx4j.wml.Text;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
/**
* This class will help you to migrate
* from MERGEFIELDs
* to use of content control data bindings.
*
* After migrating, you'll be able to
* use the OpenDoPE authoring tool to
* add repeats, conditionals, and other
* OpenDoPE features, if you need them.
*
* Limitations: this first version
* operates only on the main document part
* (ie it won't process variables in
* headers/footers, footnotes/endnotes,
* or comments)
*
* @author jharrop
* @since 3.0.0
*/
public class FromMergeFields extends AbstractMigratorUsingAnswersFormat {
private static Logger log = LoggerFactory.getLogger(FromMergeFields.class);
public WordprocessingMLPackage migrate(WordprocessingMLPackage pkgIn) throws Exception {
// TODO - test that OpenDoPE parts aren't already present
// or if they are, that this docx is using our answer format
// (since only that format is supported here)
// Clone it
WordprocessingMLPackage pkgOut = (WordprocessingMLPackage)pkgIn.clone();
// Create the CustomXML parts
createParts(pkgOut);
FieldsPreprocessor.complexifyFields(pkgOut.getMainDocumentPart() );
if(log.isDebugEnabled()) {
log.debug("complexified: "
+ XmlUtils.marshaltoString(pkgOut.getMainDocumentPart().getJaxbElement(), true));
}
// find fields
ComplexFieldLocator fl = new ComplexFieldLocator();
new TraversalUtil(pkgOut.getMainDocumentPart().getContent(), fl);
log.info("Found " + fl.getStarts().size() + " fields ");
// canonicalise and setup fieldRefs
List fieldRefs = new ArrayList();
for( P p : fl.getStarts() ) {
int index = ((ContentAccessor)p.getParent()).getContent().indexOf(p);
P newP = FieldsPreprocessor.canonicalise(p, fieldRefs);
((ContentAccessor)p.getParent()).getContent().set(index, newP);
/*
*
Hallo, lower
MERGEFIELD kundenname \* MERGEFORMAT
«Kundenname»
*/
}
// Populate
for (FieldRef fr : fieldRefs) {
if ( fr.getFldName().equals("MERGEFIELD") ) {
String instr = extractInstr(fr.getInstructions() );
// eg MERGEFIELD Kundenstrasse \* MERGEFORMAT
// or MERGEFIELD Kundenstrasse
String tmp = instr.substring( instr.indexOf("MERGEFIELD") + 10);
tmp = tmp.trim();
String key = tmp.indexOf(" ") >-1 ? tmp.substring(0, tmp.indexOf(" ")) : tmp ;
log.info("Key: '" + key + "'");
// Remove the field related runs
int end = fr.getParent().getContent().indexOf(fr.getEndRun());
int begin = fr.getParent().getContent().indexOf(fr.getBeginRun());
for (int i = end; i>=begin; i--) {
fr.getParent().getContent().remove(i);
}
// Now add a content control
List