diff --git a/build.gradle b/build.gradle index 6e2399c..56e9efc 100644 --- a/build.gradle +++ b/build.gradle @@ -13,7 +13,8 @@ dependencies { compile 'org.apache.poi:poi:+' compile 'org.apache.poi:poi-ooxml:+' compile 'org.apache.commons:commons-lang3:+' - + compile 'commons-io:commons-io:2.5' + testCompile 'org.easytesting:fest-assert:+' testCompile 'junit:junit:+' } @@ -22,3 +23,4 @@ task copyToLibs(type: Copy) { into "$buildDir/libs" from configurations.compile, configurations.testCompile } + diff --git a/src/main/java/pl/jsolve/templ4docx/cleaner/DocumentCleaner.java b/src/main/java/pl/jsolve/templ4docx/cleaner/DocumentCleaner.java index 2dd6c5c..21611ff 100644 --- a/src/main/java/pl/jsolve/templ4docx/cleaner/DocumentCleaner.java +++ b/src/main/java/pl/jsolve/templ4docx/cleaner/DocumentCleaner.java @@ -3,17 +3,14 @@ import java.util.List; import org.apache.commons.lang3.StringUtils; -import org.apache.poi.xwpf.usermodel.XWPFParagraph; -import org.apache.poi.xwpf.usermodel.XWPFRun; -import org.apache.poi.xwpf.usermodel.XWPFTable; -import org.apache.poi.xwpf.usermodel.XWPFTableCell; -import org.apache.poi.xwpf.usermodel.XWPFTableRow; +import org.apache.poi.xwpf.usermodel.*; import pl.jsolve.sweetener.text.Strings; import pl.jsolve.templ4docx.core.Docx; import pl.jsolve.templ4docx.core.VariablePattern; import pl.jsolve.templ4docx.extractor.KeyExtractor; import pl.jsolve.templ4docx.util.Key; +import pl.jsolve.templ4docx.util.ParagraphUtil; import pl.jsolve.templ4docx.variable.Variables; /** @@ -36,11 +33,9 @@ public DocumentCleaner() { */ public void clean(Docx docx, Variables variables, VariablePattern variablePattern) { List keys = keyExtractor.extractKeys(variables); - for (XWPFParagraph paragraph : docx.getXWPFDocument().getParagraphs()) { + for (XWPFParagraph paragraph : ParagraphUtil.getAllParagraphs(docx.getXWPFDocument(), true)) { clean(paragraph.getRuns(), keys, variablePattern); } - - cleanTables(docx.getXWPFDocument().getTables(), keys, variablePattern); } /** diff --git a/src/main/java/pl/jsolve/templ4docx/extractor/VariableFinder.java b/src/main/java/pl/jsolve/templ4docx/extractor/VariableFinder.java index 11cc09c..906eaba 100644 --- a/src/main/java/pl/jsolve/templ4docx/extractor/VariableFinder.java +++ b/src/main/java/pl/jsolve/templ4docx/extractor/VariableFinder.java @@ -19,6 +19,7 @@ import pl.jsolve.templ4docx.insert.TextInsert; import pl.jsolve.templ4docx.strategy.InsertStrategyChooser; import pl.jsolve.templ4docx.util.Key; +import pl.jsolve.templ4docx.util.ParagraphUtil; import pl.jsolve.templ4docx.variable.Variables; /** @@ -49,28 +50,10 @@ public VariableFinder(Variables variables) { public List find(XWPFDocument document, Variables variables) { List inserts = new ArrayList(); List keys = keyExtractor.extractKeys(variables); - for (XWPFParagraph paragraph : document.getParagraphs()) { + for (XWPFParagraph paragraph : ParagraphUtil.getAllParagraphs(document, true)) { inserts.addAll(find(paragraph, document, null, keys)); } - for (XWPFHeader header : document.getHeaderList()) { - for (XWPFParagraph paragraph : header.getParagraphs()) { - inserts.addAll(find(paragraph, document, null, keys)); - } - - findInTables(inserts, header.getTables(), keys); - } - - for (XWPFFooter footer : document.getFooterList()) { - for (XWPFParagraph paragraph : footer.getParagraphs()) { - inserts.addAll(find(paragraph, document, null, keys)); - } - - findInTables(inserts, footer.getTables(), keys); - } - - findInTables(inserts, document.getTables(), keys); - mergeTableInserts(inserts, variables); return inserts; } diff --git a/src/main/java/pl/jsolve/templ4docx/meta/DocumentMetaProcessor.java b/src/main/java/pl/jsolve/templ4docx/meta/DocumentMetaProcessor.java index ae96d99..75727a2 100644 --- a/src/main/java/pl/jsolve/templ4docx/meta/DocumentMetaProcessor.java +++ b/src/main/java/pl/jsolve/templ4docx/meta/DocumentMetaProcessor.java @@ -11,13 +11,7 @@ import java.util.regex.Pattern; import org.apache.commons.codec.digest.DigestUtils; -import org.apache.poi.xwpf.usermodel.IRunBody; -import org.apache.poi.xwpf.usermodel.XWPFDocument; -import org.apache.poi.xwpf.usermodel.XWPFParagraph; -import org.apache.poi.xwpf.usermodel.XWPFRun; -import org.apache.poi.xwpf.usermodel.XWPFTable; -import org.apache.poi.xwpf.usermodel.XWPFTableCell; -import org.apache.poi.xwpf.usermodel.XWPFTableRow; +import org.apache.poi.xwpf.usermodel.*; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBookmark; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTMarkupRange; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP; @@ -30,6 +24,7 @@ import pl.jsolve.templ4docx.extractor.KeyExtractor; import pl.jsolve.templ4docx.extractor.VariablesExtractor; import pl.jsolve.templ4docx.util.Key; +import pl.jsolve.templ4docx.util.ParagraphUtil; import pl.jsolve.templ4docx.variable.Variables; /** @@ -74,7 +69,7 @@ public void processMetaInformation(Docx docx, Variables variables, VariablePatte List keys = keyExtractor.extractKeys(variables); KeysHolder keysHolder = new KeysHolder(keys); XWPFDocument document = docx.getXWPFDocument(); - List paragraphs = getParagraphs(document); + List paragraphs = ParagraphUtil.getAllParagraphs(document, true); for (XWPFParagraph paragraph : paragraphs) { moveVariablesToSeparateRun(paragraph, keysHolder, variablePattern); markVariablesByBookmarks(paragraph, keysHolder, variablePattern); @@ -82,41 +77,11 @@ public void processMetaInformation(Docx docx, Variables variables, VariablePatte } } - /** - * @param document - * @return All document paragraphs (including paragraphs in nested tables) - */ - protected List getParagraphs(XWPFDocument document) { - List paragraphs = new ArrayList(); - paragraphs.addAll(document.getParagraphs()); - for (XWPFTable table : document.getTables()) { - paragraphs.addAll(getParagraphs(table)); - } - return paragraphs; - } - - /** - * @param table - * @return All table paragraphs (including paragraphs in nested tables) - */ - protected List getParagraphs(XWPFTable table) { - List paragraphs = new ArrayList(); - for (XWPFTableRow row : table.getRows()) { - for (XWPFTableCell cell : row.getTableCells()) { - paragraphs.addAll(cell.getParagraphs()); - for (XWPFTable cellTable : cell.getTables()) { - paragraphs.addAll(getParagraphs(cellTable)); - } - } - } - return paragraphs; - } - /** * Split every variable into separate run. * * @param paragraph - * @param keys + * @param keysHolder * @param variablePattern */ protected void moveVariablesToSeparateRun(XWPFParagraph paragraph, KeysHolder keysHolder, @@ -212,7 +177,7 @@ protected void applyRPr(XWPFRun run, CTRPr rPr) { * Every variable in separate run will by marked by bookmark. * * @param paragraph - * @param keys + * @param keysHolder * @param variablePattern */ protected void markVariablesByBookmarks(XWPFParagraph paragraph, KeysHolder keysHolder, @@ -342,7 +307,7 @@ protected List getVariableBookmarks(XWPFRun run, KeysHolder ke /** * Find bookmarks used as meta information for variables into the {@code paragraph}. * - * @param run + * @param paragraph * @param keysHolder * @return */ @@ -394,7 +359,7 @@ protected List getVariableBookmarks(XWPFParagraph paragraph, K */ protected BigInteger getMaxBookmarkId(XWPFDocument document) { BigInteger maxId = new BigInteger("0"); - for (XWPFParagraph paragraph : document.getParagraphs()) { + for (XWPFParagraph paragraph : ParagraphUtil.getAllParagraphs(document, true)) { CTP ctp = paragraph.getCTP(); for (CTBookmark bookmark : ctp.getBookmarkStartList()) { BigInteger id = bookmark.getId(); @@ -455,8 +420,7 @@ protected void alignNodes(XWPFParagraph paragraph, XWPFRun run, CTBookmark bookm * name. All other runs inside variable bookmarks will be removed. * * @param paragraph - * @param keys - * @param variablePattern + * @param keysHolder */ protected void clearVariablesInRunByBookmarks(XWPFParagraph paragraph, KeysHolder keysHolder) { List varBookmarks = getVariableBookmarks(paragraph, keysHolder); diff --git a/src/main/java/pl/jsolve/templ4docx/util/ParagraphUtil.java b/src/main/java/pl/jsolve/templ4docx/util/ParagraphUtil.java new file mode 100644 index 0000000..42641df --- /dev/null +++ b/src/main/java/pl/jsolve/templ4docx/util/ParagraphUtil.java @@ -0,0 +1,68 @@ +package pl.jsolve.templ4docx.util; + + +import org.apache.poi.xwpf.usermodel.*; + +import java.util.ArrayList; +import java.util.List; + +/** + * This class supply some methods for paragraph processing. + * + * @author Keyon + */ + +public class ParagraphUtil { + /** + * Moved from pl.jsolve.templ4docx.meta.DocumentMetaProcessor + * @param table + * @return All table paragraphs + */ + protected static List getParagraphs(XWPFTable table) { + List paragraphs = new ArrayList(); + for (XWPFTableRow row : table.getRows()) { + for (XWPFTableCell cell : row.getTableCells()) { + paragraphs.addAll(cell.getParagraphs()); + for (XWPFTable cellTable : cell.getTables()) { + paragraphs.addAll(getParagraphs(cellTable)); + } + } + } + return paragraphs; + } + + /** + * @param document + * @param includeTables if include paragraphs in tables. + * @return All document paragraphs, includes header and footer + */ + public static List getAllParagraphs(XWPFDocument document, boolean includeTables) { + List paragraphs = new ArrayList(); + paragraphs.addAll(document.getParagraphs()); + if (includeTables) { + for (XWPFTable table : document.getTables()) { + paragraphs.addAll(getParagraphs(table)); + } + } + + for (XWPFHeader header : document.getHeaderList()) { + paragraphs.addAll(header.getParagraphs()); + if (includeTables) { + for (XWPFTable table : header.getTables()) { + paragraphs.addAll(getParagraphs(table)); + } + } + } + + for (XWPFFooter footer : document.getFooterList()) { + paragraphs.addAll(footer.getParagraphs()); + if (includeTables) { + for (XWPFTable table : footer.getTables()) { + paragraphs.addAll(getParagraphs(table)); + } + } + } + + return paragraphs; + } +} diff --git a/src/main/java/pl/jsolve/templ4docx/utils/ReflectionHelper.java b/src/main/java/pl/jsolve/templ4docx/utils/ReflectionHelper.java index 8bc4c2b..a475d8d 100644 --- a/src/main/java/pl/jsolve/templ4docx/utils/ReflectionHelper.java +++ b/src/main/java/pl/jsolve/templ4docx/utils/ReflectionHelper.java @@ -74,8 +74,7 @@ public static void setFieldValueBySetter(Object object, Field field, Object valu * @param object * @param field * @return the field value of an object - * @throws IllegalAccessException - * @throws IllegalArgumentException + * @throws RuntimeException */ public static Object getFieldValue(Object object, Field field) { try { @@ -91,10 +90,9 @@ public static Object getFieldValue(Object object, Field field) { /** * @param object - * @param field + * @param fieldName * @return the field value of an object - * @throws IllegalAccessException - * @throws IllegalArgumentException + * @throws RuntimeException */ public static Object getFieldValue(Object object, String fieldName) { Collection fields = getFields(object); diff --git a/src/test/java/pl/jsolve/templ4docx/tests/meta/TestHeaderAndFooter.java b/src/test/java/pl/jsolve/templ4docx/tests/meta/TestHeaderAndFooter.java new file mode 100644 index 0000000..8a07140 --- /dev/null +++ b/src/test/java/pl/jsolve/templ4docx/tests/meta/TestHeaderAndFooter.java @@ -0,0 +1,72 @@ +package pl.jsolve.templ4docx.tests.meta; + +import org.junit.Test; +import pl.jsolve.templ4docx.core.Docx; +import pl.jsolve.templ4docx.core.VariablePattern; +import pl.jsolve.templ4docx.variable.TextVariable; +import pl.jsolve.templ4docx.variable.Variables; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +import static org.junit.Assert.assertEquals; + +/** + * @author Keyon (youngyou[dot]name[at]gmail[dot]com) + * + */ +public class TestHeaderAndFooter extends AbstractMetaTest { + + @Test + public void test() throws IOException { + String templateFileName = "meta/header-and-footer"; + InputStream is = getClass().getClassLoader().getResourceAsStream(templateFileName + ".docx"); + + Docx docx = new Docx(is); + docx.setProcessMetaInformation(true); + docx.setVariablePattern(new VariablePattern("${", "}")); + + Variables var = new Variables(); + var.addTextVariable(new TextVariable("${header01}", "Header")); + var.addTextVariable(new TextVariable("${footer01}", "Footer")); + var.addTextVariable(new TextVariable("${var01}", "Value")); + + docx.fillTemplate(var); + + String tmpPath = System.getProperty("java.io.tmpdir"); + String processedPath = String.format("%s%s%s", tmpPath, File.separator, + templateFileName + "-processed" + ".docx"); + + docx.save(processedPath); + + String text = docx.readTextContent(); + + assertEquals("This is header with two variables: Header, Value.\n" + + "This is test simple template with one variable: Value\n" + + "This is footer with two variables: Footer, Value.", text.trim()); + + is.close(); + + docx = new Docx(processedPath); + docx.setProcessMetaInformation(true); + docx.setVariablePattern(new VariablePattern("${", "}")); + + var = new Variables(); + var.addTextVariable(new TextVariable("${header01}", "Another Header")); + var.addTextVariable(new TextVariable("${footer01}", "Another Footer")); + var.addTextVariable(new TextVariable("${var01}", "Another Value")); + + docx.fillTemplate(var); + + String processedPath2 = String.format("%s%s%s", tmpPath, File.separator, + templateFileName + "-processed2" + ".docx"); + + docx.save(processedPath2); + + text = docx.readTextContent(); + assertEquals("This is header with two variables: Another Header, Another Value.\n" + + "This is test simple template with one variable: Another Value\n" + + "This is footer with two variables: Another Footer, Another Value.", text.trim()); + } +} diff --git a/src/test/resources/meta/header-and-footer.docx b/src/test/resources/meta/header-and-footer.docx new file mode 100644 index 0000000..0d6b541 Binary files /dev/null and b/src/test/resources/meta/header-and-footer.docx differ