2 回答
TA贡献1804条经验 获得超3个赞
如果您查看屏幕截图,您会在 MiddleName、Vehicle_Type 和 Reg_No 下看到红色波浪线。这意味着,它Word检测到这里可能存在拼写问题。这也存储在文件中,这就是为什么文本 [MIddleName]、[Vehicle_Type] 和 [Reg_No] 没有与它们周围的括号一起出现在一个文本行中。括号在他们自己的文本运行中,并且文本与可能的拼写问题一起标记。
这是一个众所周知的问题,一些图书馆已经尝试通过比仅在文本运行中搜索它们更复杂的方式检测文本变量来解决这个问题。例如有templ4docx。
但我更喜欢的方式是另一种。Word长期以来提供使用文本表单字段。请参阅使用表单域。请注意,这里指的是遗留表单字段,而不是 ActiveX 表单字段。
有关示例,请参阅替换 .docx 中的文本模板(Apache POI、Docx4j 或其他)。
您的案例的修改示例:
Word模板.docx:

所有灰色字段都是从开发人员选项卡插入的遗留文本表单字段。它们Text Form Field Options的Bookmark:名称是Text1, Text2, ... 并且根据需要设置默认文本。
代码:
import java.io.FileOutputStream;
import java.io.FileInputStream;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.SimpleValue;
import javax.xml.namespace.QName;
public class WordReplaceTextInFormFields {
private static void replaceFormFieldText(XWPFDocument document, String ffname, String text) {
boolean foundformfield = false;
for (XWPFParagraph paragraph : document.getParagraphs()) {
for (XWPFRun run : paragraph.getRuns()) {
XmlCursor cursor = run.getCTR().newCursor();
cursor.selectPath("declare namespace w='http://schemas.openxmlformats.org/wordprocessingml/2006/main' .//w:fldChar/@w:fldCharType");
while(cursor.hasNextSelection()) {
cursor.toNextSelection();
XmlObject obj = cursor.getObject();
if ("begin".equals(((SimpleValue)obj).getStringValue())) {
cursor.toParent();
obj = cursor.getObject();
obj = obj.selectPath("declare namespace w='http://schemas.openxmlformats.org/wordprocessingml/2006/main' .//w:ffData/w:name/@w:val")[0];
if (ffname.equals(((SimpleValue)obj).getStringValue())) {
foundformfield = true;
} else {
foundformfield = false;
}
} else if ("end".equals(((SimpleValue)obj).getStringValue())) {
if (foundformfield) return;
foundformfield = false;
}
}
if (foundformfield && run.getCTR().getTList().size() > 0) {
run.getCTR().getTList().get(0).setStringValue(text);
foundformfield = false;
//System.out.println(run.getCTR());
}
}
}
}
public static void main(String[] args) throws Exception {
XWPFDocument document = new XWPFDocument(new FileInputStream("WordTemplate.docx"));
replaceFormFieldText(document, "Text1", "Mrs.");
replaceFormFieldText(document, "Text2", "Janis");
replaceFormFieldText(document, "Text3", "Lyn");
replaceFormFieldText(document, "Text4", "Joplin");
replaceFormFieldText(document, "Text5", "Mercedes Benz");
replaceFormFieldText(document, "Text6", "1234-56-789");
replaceFormFieldText(document, "Text7", "Stuttgart");
FileOutputStream out = new FileOutputStream("WordReplaceTextInFormFields.docx");
document.write(out);
out.close();
document.close();
}
}
此代码使用并需要FAQ-N10025中提到apache poi 4.1.0的所有模式的完整 jar 进行测试。ooxml-schemas-1.4.jar
结果:

请注意,文本字段的灰色背景仅在GUI. 默认情况下不会打印出来。
优点:
表单域内容只能整体格式化。所以表单字段内容永远不会撕裂。
文档可以受到保护,因此只能填写表单字段。然后模板也可以用作表单Word GUI。
TA贡献1806条经验 获得超5个赞
如果您正在寻找一种超级快速修复来防止将文本拆分为多个运行,以便它可以被 java 程序识别/读取,请执行以下操作:
在一次运行中复制您想要的文本
将其粘贴到记事本中(删除所有 docx 格式)
将该文本复制并粘贴到word文档中,点击保存。
现在它将作为一次运行插入。
添加回答
举报
