Docx4j – 如何用值替换占位符

我一直在尝试使用示例FieldMailMerge和VariableReplace,但似乎无法运行本地测试用例。 我基本上试图从一个docx模板文档开始,让它从一个模板创建x docx文档并替换变量。

在下面的代码中, docx4jReplaceSimpleTest()尝试替换单个变量但未能这样做。 模板文件中的$ {}值将作为处理的一部分被删除,因此我相信它正在找到它们但不会因某些原因替换它们。 据我所知,这可能是由于示例代码的注释中所解释的格式化,但是为了让事情正常进行故障排除,我仍在尝试它。

docx4jReplaceTwoPeopleTest()下面的代码中,我想要工作的那个,我正在尝试用我认为正确的方式来做,但那不是找到或替换任何东西。 它甚至没有从docx文件中删除$ {}。

 public static void main(String[] args) throws Exception { docx4jReplaceTwoPeopleTest(); docx4jReplaceSimpleTest(); } private static void docx4jReplaceTwoPeopleTest() throws Exception { String docxFile = "C:/temp/template.docx"; WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(new java.io.File(docxFile)); List<Map> data = new ArrayList<Map>(); Map map1 = new HashMap(); map1.put(new DataFieldName("Person.Firstname"), "myFirstname"); map1.put(new DataFieldName("Person.Lastname"), "myLastname"); data.add(map1); Map map2 = new HashMap(); map2.put(new DataFieldName("Person.Firstname"), "myFriendsFirstname"); map2.put(new DataFieldName("Person.Lastname"), "myFriendsLastname"); data.add(map2); org.docx4j.model.fields.merge.MailMerger.setMERGEFIELDInOutput(OutputField.KEEP_MERGEFIELD); int x=0; for(Map docMapping: data) { org.docx4j.model.fields.merge.MailMerger.performMerge(wordMLPackage, docMapping, true); wordMLPackage.save(new java.io.File("C:/temp/OUT__MAIL_MERGE_" + x++ + ".docx") ); } } private static void docx4jReplaceSimpleTest() throws Exception { String docxFile = "C:/temp/template.docx"; WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(new java.io.File(docxFile)); HashMap mappings = new HashMap(); mappings.put("Person.Firstname", "myFirstname"); mappings.put("Person.Lastname", "myLastname"); MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart(); documentPart.variableReplace(mappings); wordMLPackage.save(new java.io.File("C:/temp/OUT_SIMPLE.docx") ); } 

docx文件包含以下文本(不进行格式化):

 This is a letter to someone Hi ${Person.Firstname} ${Person.Lastname}, How are you? Thank you again. I wish to see you soon ${Person.Firstname} Regards, Someone 

请注意,我也尝试将Person.Firstname替换为至少两次。 由于姓氏甚至没有被替换,我不认为这与它有任何关系,但我是为了以防万一我添加它。

我有同样的问题,当然我不能强迫用户在编写单词文档时做一些额外的事情,所以我决定只编写一个算法来扫描整个文档中的表达式追加运行后运行,插入替换值并删除表达式第二轮。 如果其他人可能需要它,我就是这么做的。 我从某个地方上课,所以它可能很熟悉。 我刚刚添加了方法searchAndReplace()

 package com.my.docx4j; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import org.docx4j.openpackaging.exceptions.Docx4JException; import org.docx4j.openpackaging.packages.WordprocessingMLPackage; import org.docx4j.wml.ContentAccessor; import org.docx4j.wml.Text; public class Docx4j { public static void main(String[] args) throws Docx4JException, IOException, JAXBException { String filePath = "C:\\Users\\markamm\\Documents\\tmp\\"; String file = "Hello.docx"; Docx4j docx4j = new Docx4j(); WordprocessingMLPackage template = docx4j.getTemplate(filePath+file); // MainDocumentPart documentPart = template.getMainDocumentPart(); List texts = getAllElementFromObject( template.getMainDocumentPart(), Text.class); searchAndReplace(texts, new HashMap(){ { this.put("${abcd_efg.soanother_hello_broken_shit}", "Company Name here..."); this.put("${I_dont_know}", "Hmmm lemme see"); this.put("${${damn.right_lol}", "Gotcha!!!"); this.put("${one_here_and}", "Firstname"); this.put("${one}", "ChildA"); this.put("${two}", "ChildB"); this.put("${three}", "ChildC"); } @Override public String get(Object key) { // TODO Auto-generated method stub return super.get(key); } }); docx4j.writeDocxToStream(template, filePath+"Hello2.docx"); } public static void searchAndReplace(List texts, Map values){ // -- scan all expressions // Will later contain all the expressions used though not used at the moment List els = new ArrayList(); StringBuilder sb = new StringBuilder(); int PASS = 0; int PREPARE = 1; int READ = 2; int mode = PASS; // to nullify List toNullify = new ArrayList(); int[] currentNullifyProps = new int[4]; // Do scan of els and immediately insert value for(int i = 0; i0) for(int i = 0; i=floor && head<=ceil)){ nvalSB.append(c); } if(j>currentNullifyProps[3] && i>=currentNullifyProps[2]){ toNullify.remove(0); if(toNullify.size()==0) { currentNullifyProps = null; continue; } currentNullifyProps = toNullify.get(0); } } textElement.setValue(nvalSB.toString()); } } private WordprocessingMLPackage getTemplate(String name) throws Docx4JException, FileNotFoundException { WordprocessingMLPackage template = WordprocessingMLPackage .load(new FileInputStream(new File(name))); return template; } private static List getAllElementFromObject(Object obj, Class toSearch) { List result = new ArrayList(); if (obj instanceof JAXBElement) obj = ((JAXBElement) obj).getValue(); if (obj.getClass().equals(toSearch)) result.add(obj); else if (obj instanceof ContentAccessor) { List children = ((ContentAccessor) obj).getContent(); for (Object child : children) { result.addAll(getAllElementFromObject(child, toSearch)); } } return result; } private void replacePlaceholder(WordprocessingMLPackage template, String name, String placeholder) { List texts = getAllElementFromObject( template.getMainDocumentPart(), Text.class); for (Object text : texts) { Text textElement = (Text) text; if (textElement.getValue().equals(placeholder)) { textElement.setValue(name); } } } private void writeDocxToStream(WordprocessingMLPackage template, String target) throws IOException, Docx4JException { File f = new File(target); template.save(f); } } 

问题是我试图在docx文件中创建占位符只是纯文本。 我应该做的是使用Word中的MergeFieldfunction,我并不完全理解和欣赏,因此存在混淆。 基本上我不知道这是文档中的意思,因为我从来没有使用它,我只是假设它仍然是某种xml文本替换。

话虽如此,找到这个Wordfunction的一个很好的解释仍然相当困难。 看了几十个解释后,我仍然找不到这个Wordfunction的清晰解释。 我能找到的最佳解释可以在这里找到 。 基本上你想做第3步。

话虽这么说,一旦我在Word中创建MergeFields并运行代码,它就能完美运行。 使用的方法是docx4jReplaceTwoPeopleTest问题不在于代码,而在于我对Word中的工作原理的理解。