Если вы посмотрите на снимок экрана, вы увидите красную волнистую линию под MiddleName, Vehicle_Type и Reg_No.Это означает, что Word
обнаружил здесь возможную орфографическую проблему.Это также сохраняется в файле, и поэтому тексты [MIddleName], [Vehicle_Type] и [Reg_No] не объединены в одном текстовом цикле с окружающими их скобками.Скобки имеют свои собственные текстовые прогоны, а также тексты вместе с отмеченной возможной проблемой правописания.
Это хорошо известная проблема, и некоторые библиотеки уже пытаются решить ее, обнаруживая текстовые переменные более сложным способом, чем толькопоиск их в текстовых прогонах.Например, templ4docx .
Но я предпочитаю другой путь.Word
долгое время обеспечивает использование текстовых полей формы.См. Работа с полями формы .Обратите внимание, что подразумеваются устаревшие поля формы, а не поля ActiveX.
См. Замена текстовых шаблонов внутри .docx (Apache POI, Docx4j или др.) для примера.
Модифицированный пример для вашего случая:
WordTemplate.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);
//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();
}
}
Этот кодпротестировано с использованием apache poi 4.1.0
и нуждается в полной банке всех схем ooxml-schemas-1.4.jar
, как указано в FAQ-N10025 .
Результат:
Обратите внимание, что серый фон текстовых полей виден только в GUI
.Он не будет распечатан по умолчанию.
Преимущества:
Содержимое поля формы может быть отформатировано только как целое.Таким образом, содержимое поля формы никогда не разорвется.
Документ может быть защищен, поэтому возможно заполнение только полей формы.Тогда шаблон можно использовать как форму в Word
GUI
тоже.