我有一个word文档用作模板。在这个模板中,我有一些包含预定义要点的表。现在我试图用一组字符串替换占位符字符串。
我完全被这件事缠住了。我的简化方法是这样的。
replaceKeyValue.put("[DescriptionOfItem]", new HashSet<>(Collections.singletonList("This is the description")));
replaceKeyValue.put("[AllowedEntities]", new HashSet<>(Arrays.asList("a", "b")));
replaceKeyValue.put("[OptionalEntities]", new HashSet<>(Arrays.asList("c", "d")));
replaceKeyValue.put("[NotAllowedEntities]", new HashSet<>(Arrays.asList("e", "f")));
try (XWPFDocument template = new XWPFDocument(OPCPackage.open(file))) {
template.getTables().forEach(
xwpfTable -> xwpfTable.getRows().forEach(
xwpfTableRow -> xwpfTableRow.getTableCells().forEach(
xwpfTableCell -> replaceInCell(replaceKeyValue, xwpfTableCell)
)
));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
template.write(baos);
return new ByteArrayResource(baos.toByteArray());
} finally {
if (file.exists()) {
file.delete();
}
}
private void replaceInCell(Map<String, Set<String>> replacementsKeyValuePairs, XWPFTableCell xwpfTableCell) {
for (XWPFParagraph xwpfParagraph : xwpfTableCell.getParagraphs()) {
for (Map.Entry<String, Set<String>> replPair : replacementsKeyValuePairs.entrySet()) {
String keyToFind = replPair.getKey();
Set<String> replacementStrings = replacementsKeyValuePairs.get(keyToFind);
if (xwpfParagraph.getText().contains(keyToFind)) {
replacementStrings.forEach(replacementString -> {
XWPFParagraph paragraph = xwpfTableCell.addParagraph();
XWPFRun run = paragraph.createRun();
run.setText(replacementString);
});
}
}
}
我期望在当前单元格中添加更多的项目符号。我错过了什么吗?段落包含占位符字符串和格式。
谢谢你的帮助!
更新:这是模板的一部分。我想自动搜索术语并替换它们。搜索工作到目前为止。但是试图替换项目符号以不可定位的NullPointer
结束。使用字段会更容易吗?不过,我需要保留项目符号样式。
更新2:添加下载链接并更新代码。如果我迭代这些段落,似乎我不能改变它们。我得到一个空指针。下载链接:文字模板
由于Microsoft Word
在其存储的不同运行中如何划分文本非常非常奇怪,如果没有一个完整的示例,包括所有代码和所讨论的Word
文档,则无法回答这些问题。拥有一个通用的可用代码来向Word
文档添加内容似乎是不可能的,除非所有的添加或替换仅在字段中(表单字段或内容控件或邮件合并字段)。
所以我下载了你的WordTemplate.docx
看起来是这样的:
然后我运行了以下代码:
import java.io.*;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR;
import org.apache.xmlbeans.XmlCursor;
import java.util.*;
import java.math.BigInteger;
public class WordReadAndRewrite {
static void addItems(XWPFTableCell cell, XWPFParagraph paragraph, Set<String> items) {
XmlCursor cursor = null;
XWPFRun run = null;
CTR cTR = null; // for a deep copy of the run's low level object
BigInteger numID = paragraph.getNumID();
int indentationLeft = paragraph.getIndentationLeft();
int indentationHanging = paragraph.getIndentationHanging();
boolean first = true;
for (String item : items) {
if (first) {
for (int r = paragraph.getRuns().size()-1; r > 0; r--) {
paragraph.removeRun(r);
}
run = (paragraph.getRuns().size() > 0)?paragraph.getRuns().get(0):null;
if (run == null) run = paragraph.createRun();
run.setText(item, 0);
cTR = (CTR)run.getCTR().copy(); // take a deep copy of the run's low level object
first = false;
} else {
cursor = paragraph.getCTP().newCursor();
boolean thereWasParagraphAfter = cursor.toNextSibling(); // move cursor to next paragraph
// because the new paragraph shall be **after** that paragraph
// thereWasParagraphAfter is true if there is a next paragraph, else false
if (thereWasParagraphAfter) {
paragraph = cell.insertNewParagraph(cursor); // insert new paragraph if there are next paragraphs in cell
} else {
paragraph = cell.addParagraph(); // add new paragraph if there are no other paragraphs present in cell
}
paragraph.setNumID(numID); // set template paragraph's numbering Id
paragraph.setIndentationLeft(indentationLeft); // set template paragraph's indenting from left
if (indentationHanging != -1) paragraph.setIndentationHanging(indentationHanging); // set template paragraph's hanging indenting
run = paragraph.createRun();
if (cTR != null) run.getCTR().set(cTR); // set template paragraph's run formatting
run.setText(item, 0);
}
}
}
public static void main(String[] args) throws Exception {
Map<String, Set<String>> replaceKeyValue = new HashMap<String, Set<String>>();
replaceKeyValue.put("[AllowedEntities]", new HashSet<>(Arrays.asList("allowed 1", "allowed 2", "allowed 3")));
replaceKeyValue.put("[OptionalEntities]", new HashSet<>(Arrays.asList("optional 1", "optional 2", "optional 3")));
replaceKeyValue.put("[NotAllowedEntities]", new HashSet<>(Arrays.asList("not allowed 1", "not allowed 2", "not allowed 3")));
XWPFDocument document = new XWPFDocument(new FileInputStream("WordTemplate.docx"));
List<XWPFTable> tables = document.getTables();
for (XWPFTable table : tables) {
List<XWPFTableRow> rows = table.getRows();
for (XWPFTableRow row : rows) {
List<XWPFTableCell> cells = row.getTableCells();
for (XWPFTableCell cell : cells) {
int countParagraphs = cell.getParagraphs().size();
for (int p = 0; p < countParagraphs; p++) { // do not for each since new paragraphs were added
XWPFParagraph paragraph = cell.getParagraphArray(p);
String placeholder = paragraph.getText();
placeholder = placeholder.trim(); // this is the tricky part to get really the correct placeholder
Set<String> items = replaceKeyValue.get(placeholder);
if (items != null) {
addItems(cell, paragraph, items);
}
}
}
}
}
FileOutputStream out = new FileOutputStream("Result.docx");
document.write(out);
out.close();
document.close();
}
}
Result.docx
看起来是这样的:
代码在Word
文档中的表格单元格中循环,并查找恰好包含占位符的段落。这甚至可能是一个棘手的部分,因为占位符可能被拆分成不同的文本,由Word
运行。如果找到了,它会运行一个方法addItems
,该方法将找到的段落作为编号和缩进的模板(不过可能是不可过滤的)。然后,它在找到的段落的第一个文本运行中设置第一个新项,并删除可能存在的所有其他文本运行。然后确定是否必须在单元格中插入或添加新段落。为此,将使用XmlCursor
。在新插入或添加的段落中,其他项目被放置,编号和缩进设置取自占位符的段落。
如前所述,这是用于展示如何做的原则的代码。它必须进行非常大的扩展才能通用。在我看来,那些在Word
文档中使用文本占位符替换文本的试验并不太好。Word
文档中可变文本的占位符应该是字段。这可以是表单字段、内容控件或邮件合并字段。与文本占位符相比,字段的优势在于Word
知道字段是可变文本的实体。它不会因为多种奇怪的原因将它们拆分为多个文本运行,就像通常对普通文本所做的那样。
有没有办法将文件附加到MS Word文档中?我的意思与您将MS Excel文件拖放到MS Word中的方式相同。它显示MS Excel图标和文件名,双击打开附件。 我的情况来自以前的html文件,我导入使用XHTMLImporter.convert.现在超文本标记语言引用附件下载几个地方,并希望将这些文件附加到适当的MS Word文档。
问题描述 (Problem Description) 如何使用Java将表添加到word文档。 解决方案 (Solution) 以下是使用Java将表添加到word文档的程序。 import java.io.File; import java.io.FileOutputStream; import org.apache.poi.xwpf.usermodel.XWPFDocument; import
我正在尝试创建一个包含多列的word文档。这样做(而不是使用表)的原因是,数据将跨越多个页面,在添加到新页面之前,我只能用列填充整个页面。 可以用ApachePOI实现吗?谢谢
在使用ApachePOI写入word文档时,对于必须根据某个“计数”动态复制段落的位置,这些段落的标题必须按照章节顺序编号。假设它是word文档中的第7节,那么其中每个段落的标题应按顺序编号为7.1、7.2等。 尽管我看到了一些解决方案,其中考虑了word文档的xml,并使用了XWPFN编号。 还有其他更简单的方法吗? 或 如果我的word模板已经有了一个带有编号标题的段落,并且我必须多次复制相同
我想使用openxml在word文档中添加一个水平形状。 我试图使用OpenXML生产力工具粘贴代码,但在打开生成的文件时出现了一些错误http://schemas.microsoft.com/office/word/2010/wordml:anchorId“属性未声明)