plutext / docx4j

JAXB-based Java library for Word docx, Powerpoint pptx, and Excel xlsx files
https://www.docx4java.org/
2.12k stars 1.2k forks source link

MailMerge and totally unrelated nested fields #183

Open johannes-tenschert opened 8 years ago

johannes-tenschert commented 8 years ago

I needed MERGEFIELDs as well as other nested fields (IF, special page numbering that doesn't need anything from any mergefield). This either yielded a stack overflow in FieldRef.java:304 (to log! the error...) or sometimes no result for the mergefield.

I looked into it and found three reasons for the errors:

Since at least according to your forum you currently have no desire to support nested merge fields, I propose to just ignore and preserve other types of nested fields. I played around a little bit and this is the minimum of necessary changes I came up with:

diff --git a/src/main/java/org/docx4j/model/fields/FieldRef.java b/src/main/java/org/docx4j/model/fields/FieldRef.java
index b54bba8..0a39a88 100644
--- a/src/main/java/org/docx4j/model/fields/FieldRef.java
+++ b/src/main/java/org/docx4j/model/fields/FieldRef.java
@@ -301,8 +301,7 @@ public class FieldRef {
            if (o instanceof FieldRef) {
                // contains a nested field?!
                FieldRef nested = (FieldRef)o;
-               log.error("Nested field " + nested.getFldName() );              
-               
+               log.error("Nested field detected");
            } else {
                 if(log.isErrorEnabled()) {
                     log.error(XmlUtils.marshaltoString(instructions.get(0), true, true));
@@ -310,7 +309,15 @@ public class FieldRef {
            }
            return null;
        }
-   }   
+   }
+
+   /**
+    * Check whether this field is nested
+    */
+   public boolean isNestedField() {
+       Object o = XmlUtils.unwrap(instructions.get(0));
+       return o instanceof FieldRef;
+   }

    private ContentAccessor parent;
    public ContentAccessor getParent() {
diff --git a/src/main/java/org/docx4j/model/fields/FieldsPreprocessor.java b/src/main/java/org/docx4j/model/fields/FieldsPreprocessor.java
index 16093d9..ee837fe 100644
--- a/src/main/java/org/docx4j/model/fields/FieldsPreprocessor.java
+++ b/src/main/java/org/docx4j/model/fields/FieldsPreprocessor.java
@@ -252,6 +252,8 @@ public class FieldsPreprocessor {

        if (fieldRef.isLock()) return true;

+       if (fieldRef.isNestedField())
+           return true;

        String fldName = fieldRef.getFldName();
        if (fldName==null) return true;
diff --git a/src/main/java/org/docx4j/model/fields/merge/MailMerger.java b/src/main/java/org/docx4j/model/fields/merge/MailMerger.java
index cb794fd..25831f8 100644
--- a/src/main/java/org/docx4j/model/fields/merge/MailMerger.java
+++ b/src/main/java/org/docx4j/model/fields/merge/MailMerger.java
@@ -493,7 +493,9 @@ public class MailMerger {

        // Populate
        for (FieldRef fr : fieldRefs) {
-           
+           if (fr.isNestedField())
+               continue;
+
            if ( fr.getFldName().equals("MERGEFIELD") ) {

                String instr = extractInstr(fr.getInstructions() );

At least for my templates this resolved the issue.

maartenflippo commented 5 years ago

Currently I have the same issue, where nested fields trigger a StackOverflow exception. I am willing to submit the changes proposed by @johannes-tenschert as a pull-request if that was not done already. It would at least allow for the library to be used if nested fields are present without crashes.