我一直在尝试完成示例 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<DataFieldName, String>> data = new ArrayList<Map<DataFieldName, String>>();
Map<DataFieldName, String> map1 = new HashMap<DataFieldName, String>();
map1.put(new DataFieldName("Person.Firstname"), "myFirstname");
map1.put(new DataFieldName("Person.Lastname"), "myLastname");
data.add(map1);
Map<DataFieldName, String> map2 = new HashMap<DataFieldName, String>();
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<DataFieldName, String> 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<String, String> mappings = new HashMap<String, String>();
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 两次。由于姓氏甚至没有被替换,我认为这与它没有任何关系,但我添加它以防万一。
最佳答案
我遇到了同样的问题,当然我不能强制用户在撰写他们的 word 文档时做一些额外的事情,所以我决定只编写一个算法来扫描整个文档以查找在运行后追加的表达式,插入替换值和在第二次运行中删除表达式。如果其他人可能需要它,下面就是我所做的。我从某个地方得到了这门课,所以它可能很熟悉。我刚刚添加了方法 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<Object> texts = getAllElementFromObject(
template.getMainDocumentPart(), Text.class);
searchAndReplace(texts, new HashMap<String, String>(){
{
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<Object> texts, Map<String, String> values){
// -- scan all expressions
// Will later contain all the expressions used though not used at the moment
List<String> els = new ArrayList<String>();
StringBuilder sb = new StringBuilder();
int PASS = 0;
int PREPARE = 1;
int READ = 2;
int mode = PASS;
// to nullify
List<int[]> toNullify = new ArrayList<int[]>();
int[] currentNullifyProps = new int[4];
// Do scan of els and immediately insert value
for(int i = 0; i<texts.size(); i++){
Object text = texts.get(i);
Text textElement = (Text) text;
String newVal = "";
String v = textElement.getValue();
// System.out.println("text: "+v);
StringBuilder textSofar = new StringBuilder();
int extra = 0;
char[] vchars = v.toCharArray();
for(int col = 0; col<vchars.length; col++){
char c = vchars[col];
textSofar.append(c);
switch(c){
case '$': {
mode=PREPARE;
sb.append(c);
// extra = 0;
} break;
case '{': {
if(mode==PREPARE){
sb.append(c);
mode=READ;
currentNullifyProps[0]=i;
currentNullifyProps[1]=col+extra-1;
System.out.println("extra-- "+extra);
} else {
if(mode==READ){
// consecutive opening curl found. just read it
// but supposedly throw error
sb = new StringBuilder();
mode=PASS;
}
}
} break;
case '}': {
if(mode==READ){
mode=PASS;
sb.append(c);
els.add(sb.toString());
newVal +=textSofar.toString()
+(null==values.get(sb.toString())?sb.toString():values.get(sb.toString()));
textSofar = new StringBuilder();
currentNullifyProps[2]=i;
currentNullifyProps[3]=col+extra;
toNullify.add(currentNullifyProps);
currentNullifyProps = new int[4];
extra += sb.toString().length();
sb = new StringBuilder();
} else if(mode==PREPARE){
mode = PASS;
sb = new StringBuilder();
}
}
default: {
if(mode==READ) sb.append(c);
else if(mode==PREPARE){
mode=PASS;
sb = new StringBuilder();
}
}
}
}
newVal +=textSofar.toString();
textElement.setValue(newVal);
}
// remove original expressions
if(toNullify.size()>0)
for(int i = 0; i<texts.size(); i++){
if(toNullify.size()==0) break;
currentNullifyProps = toNullify.get(0);
Object text = texts.get(i);
Text textElement = (Text) text;
String v = textElement.getValue();
StringBuilder nvalSB = new StringBuilder();
char[] textChars = v.toCharArray();
for(int j = 0; j<textChars.length; j++){
char c = textChars[j];
if(null==currentNullifyProps) {
nvalSB.append(c);
continue;
}
// I know 100000 is too much!!! And so what???
int floor = currentNullifyProps[0]*100000+currentNullifyProps[1];
int ceil = currentNullifyProps[2]*100000+currentNullifyProps[3];
int head = i*100000+j;
if(!(head>=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<Object> getAllElementFromObject(Object obj,
Class<?> toSearch) {
List<Object> result = new ArrayList<Object>();
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<Object> 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);
}
}
关于java - Docx4j - 如何用值替换占位符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20484722/
在我的应用程序中,我需要能够找到所有数字子字符串,然后扫描每个子字符串,找到第一个匹配范围(例如5到15之间)的子字符串,并将该实例替换为另一个字符串“X”。我的测试字符串s="1foo100bar10gee1"我的初始模式是1个或多个数字的任何字符串,例如,re=Regexp.new(/\d+/)matches=s.scan(re)给出["1","100","10","1"]如果我想用“X”替换第N个匹配项,并且只替换第N个匹配项,我该怎么做?例如,如果我想替换第三个匹配项“10”(匹配项[2]),我不能只说s[matches[2]]="X"因为它做了两次替换“1fooX0barXg
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
我正在尝试用ruby中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了
我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www
我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我
什么是ruby的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht
这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/
HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候
遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg
我基本上来自Java背景并且努力理解Ruby中的模运算。(5%3)(-5%3)(5%-3)(-5%-3)Java中的上述操作产生,2个-22个-2但在Ruby中,相同的表达式会产生21个-1-2.Ruby在逻辑上有多擅长这个?模块操作在Ruby中是如何实现的?如果将同一个操作定义为一个web服务,两个服务如何匹配逻辑。 最佳答案 在Java中,模运算的结果与被除数的符号相同。在Ruby中,它与除数的符号相同。remainder()在Ruby中与被除数的符号相同。您可能还想引用modulooperation.