java - 如何在不丢失格式的情况下使用 POI 替换“.docx”中的书签?
问题描述
我正在尝试用值替换书签。
private FileInputStream fis = new FileInputStream(new File("D:\\test.docx"));
private XWPFDocument document = new XWPFDocument(fis);
List<XWPFParagraph> paraList = this.document.getParagraphs();
private final void procParaList(List<XWPFParagraph> paraList, String bookmarkName, String bookmarkValue) {
Iterator<XWPFParagraph> paraIter = null;
XWPFParagraph para = null;
List<CTBookmark> bookmarkList = null;
Iterator<CTBookmark> bookmarkIter = null;
CTBookmark bookmark = null;
XWPFRun run = null;
Node nextNode = null;
paraIter = paraList.iterator();
while (paraIter.hasNext()) {
para = paraIter.next();
bookmarkList = para.getCTP().getBookmarkStartList();
bookmarkIter = bookmarkList.iterator();
while (bookmarkIter.hasNext()) {
bookmark = bookmarkIter.next();
if (bookmark.getName().equals(bookmarkName)) {
run = para.createRun();
run.setText(bookmarkValue);
nextNode = bookmark.getDomNode().getNextSibling();
while (!(nextNode.getNodeName().contains("bookmarkEnd"))) {
para.getCTP().getDomNode().removeChild(nextNode);
nextNode = bookmark.getDomNode().getNextSibling();
}
para.getCTP().getDomNode().insertBefore(run.getCTR().getDomNode(), nextNode);
}
}
}
}
我可以将书签替换为值,但它与书签文本的格式(字体系列、字体大小、颜色等)不同。
任何人都可以提供一些建议。
解决方案
如前所述,我相信这是您的确切用例,官方存档链接 帮助 请重点关注使用Node styleNode复制样式信息。
/**
* Replace the text - if any - contained between the bookmarkStart and
it's
* matching bookmarkEnd tag with the text specified. The technique used
will
* resemble that employed when inserting text after the bookmark. In
short,
* the code will iterate along the nodes until it encounters a matching
* bookmarkEnd tag. Each node encountered will be deleted unless it is
the
* final node before the bookmarkEnd tag is encountered and it is a
* character run. If this is the case, then it can simply be updated to
* contain the text the users wishes to see inserted into the document.
If
* the last node is not a character run, then it will be deleted, a new
run
* will be created and inserted into the paragraph between the
bookmarkStart
* and bookmarkEnd tags.
*
* @param run An instance of the XWPFRun class that encapsulates the
text
* that is to be inserted into the document following the bookmark.
*/
private void replaceBookmark(XWPFRun run) {
Node nextNode = null;
Node styleNode = null;
Node lastRunNode = null;
Node toDelete = null;
NodeList childNodes = null;
Stack<Node> nodeStack = null;
boolean textNodeFound = false;
boolean foundNested = true;
int bookmarkStartID = 0;
int bookmarkEndID = -1;
int numChildNodes = 0;
nodeStack = new Stack<Node>();
bookmarkStartID = this._ctBookmark.getId().intValue();
nextNode = this._ctBookmark.getDomNode();
nodeStack.push(nextNode);
// Loop through the nodes looking for a matching bookmarkEnd tag
while (bookmarkStartID != bookmarkEndID) {
nextNode = nextNode.getNextSibling();
nodeStack.push(nextNode);
// If an end tag is found, does it match the start tag? If so,
end
// the while loop.
if (nextNode.getNodeName().contains(Bookmark.BOOKMARK_END_TAG))
{
try {
bookmarkEndID = Integer.parseInt(
nextNode.getAttributes().getNamedItem(
Bookmark.BOOKMARK_ID_ATTR_NAME).getNodeValue());
} catch (NumberFormatException nfe) {
bookmarkEndID = bookmarkStartID;
}
}
//else {
// Place a reference to the node on the nodeStack
// nodeStack.push(nextNode);
//}
}
// If the stack of nodes found between the bookmark tags is not
empty
// then they have to be removed.
if (!nodeStack.isEmpty()) {
// Check the node at the top of the stack. If it is a run, get
it's
// style - if any - and apply to the run that will be replacing
it.
//lastRunNode = nodeStack.pop();
lastRunNode = nodeStack.peek();
if ((lastRunNode.getNodeName().equals(Bookmark.RUN_NODE_NAME)))
{
styleNode = this.getStyleNode(lastRunNode);
if (styleNode != null) {
run.getCTR().getDomNode().insertBefore(
styleNode.cloneNode(true),
run.getCTR().getDomNode().getFirstChild());
}
}
推荐阅读
- ios - 我的应用程序使用 CoreData 变得越来越大
- sqlite - 我可以使用 DB Browser for SQLite 在 SQLite 表设计中添加注释吗?
- visual-studio-code - VSCode 选择片段
- javascript - 对 Laravel 资源控制器的 AJAX 请求,最佳实践
- visual-build-professional - 构建完成后自动退出 Visual Build Professional 工具?
- python - 将 Excel 相关窗口与 Pandas 相关窗口对齐
- node.js - 无法安装 aerospike,在“node-gyp 重建”步骤中使 aerospike 失败
- html - (Angular)如何将标签动态插入
标签
- sql - SQLite - where 子句不适用于两列
- java - 无法解析 ':app@debugAndroidTest/compileClasspath' 的依赖关系:无法为文件内容创建 MD5 哈希