更详细的word操作===》》https://blog.csdn.net/m0_73006373/article/details/138285676?spm=1001.2014.3001.5501
1.获取word文档对象
写出两种不同获取word文档对象方式,通过文件服务器路径,和文件流的方式,请自行参考!
/**
* 根据文档服务器路径获取文档对象
* @param wordPath
* @return
*/
public static XWPFDocument getXWPFDocument(String wordPath) {
FileInputStream fis = null;
XWPFDocument document = null;
try {
fis = new FileInputStream(new File(wordPath));
document = new XWPFDocument(fis);
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
} finally {
if (fis != null) {
try {
fis.close();
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
}
return document;
}
/**
* 根据文联流获取文档对象
* @param inputStream
* @return
*/
public static XWPFDocument getXWPFDocument(InputStream inputStream) {
XWPFDocument document = null;
try {
document = new XWPFDocument(inputStream);
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
}
return document;
}
2. 通过poi获取word内所有书签
注意:_GoBack书签貌似是wps自带的隐藏书签,如果不剔除的话会多出这么个书签,并且表格部分书签和文字部分书签获取方法不同!
/**
* 获取word文档内所有书签
*
* @param document
* @return
*/
public static List<String> getBookMarksName(XWPFDocument document) {
List<String> bookMarkList = new ArrayList<>();
try {
// 获取所有段落
List<XWPFParagraph> paragraphs = document.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
// 检查段落中是否有书签
List<CTBookmark> bookmarks = paragraph.getCTP().getBookmarkStartList();
for (CTBookmark bookmark : bookmarks) {
if (!bookmark.getName().equals("_GoBack")) {
bookMarkList.add(bookmark.getName());
}
}
}
// 获取所有表格
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) {
// 处理单元格中的段落
List<XWPFParagraph> cellParagraphs = cell.getParagraphs();
for (XWPFParagraph paragraph : cellParagraphs) {
// 检查段落中是否有书签
List<CTBookmark> bookmarks = paragraph.getCTP().getBookmarkStartList();
for (CTBookmark bookmark : bookmarks) {
if (!bookmark.getName().equals("_GoBack")) {
bookMarkList.add(bookmark.getName());
}
}
}
}
}
}
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
return bookMarkList;
}
3.通过poi获取word内所有占位符
只需通过文档对象加正则表达式即刻获取占位符,另外此处仅写出了对文本部分占位符获取,表格部分不适应噢;
/**
* 获取文档内所有占位符
*
* @param document 文档对象
* @param regex 占位符正则表达式
* @return
*/
public static List<String> getPlaceholderName(XWPFDocument document, String regex) {
List<String> matchedTextList = new ArrayList<>();
for (XWPFParagraph paragraph : document.getParagraphs()) {
String text = paragraph.getText();
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
matchedTextList.add(matcher.group());
}
}
return matchedTextList;
}
4.替换占位符处文本内容
问题:指定书签位置替换,插入文本信息,会删除不属于书签所在内容
原因:获取书签位置段落,存在书签只是段落其中的一个或者多个run,如果移除段落中的run,则会删除多余内容,无法达到预期效果
/**
* 替换占位符位置文本
* @param document 文档对象
* @param placeholder 占位符
* @param replacementText 要替换占位符的新文本
*/
public static XWPFDocument replacePlaceholder(XWPFDocument document, String placeholder, String replacementText) {
for (XWPFParagraph paragraph : document.getParagraphs()) {
StringBuilder paragraphText = new StringBuilder();
// 遍历段落中的每个文本片段
for (XWPFRun run : paragraph.getRuns()) {
String text = run.getText(0);
if (text != null) {
paragraphText.append(text);
}
}
// 获取段落中的文本
String fullText = paragraphText.toString();
// 寻找占位符位置
int startIndex = fullText.indexOf(placeholder);
boolean replaceText = false;
while (startIndex >= 0) {
// 定位到包含占位符的文本片段的位置
int endIndex = startIndex + placeholder.length();
// 替换占位符文本片段
for (int i = 0; i < paragraph.getRuns().size(); i++) {
XWPFRun run = paragraph.getRuns().get(i);
String runText = run.getText(0);
if (runText != null) {
int runLength = runText.length();
if (startIndex < runLength && placeholder.contains(runText) && replaceText == false) {
replaceText = true;
int relativeStartIndex = Math.max(startIndex, 0);
int relativeEndIndex = Math.min(endIndex, runLength);
String newText = runText.substring(0, relativeStartIndex) + replacementText + runText.substring(relativeEndIndex);
run.setText(newText, 0);
} else if (startIndex < runLength && placeholder.contains(runText) && replaceText){
run.setText("", 0);
}
startIndex -= runLength;
endIndex -= runLength;
}
}
}
}
return document;
}
5.替换书签部分文本内容
问题1:指定书签位置替换,插入文本信息,会删除不属于书签所在内容
原因:获取书签位置段落,存在书签只是段落其中的一个或者多个run,如果移除段落中的run,则会删除多余内容,无法达到预期效果
问题2:书签内容替换后,替换文本格式发生改变
原因:由于我是创建了一个新的运行元素 XWPFRun run = xwpfParagraph.createRun();
(run就是段落对象的下一层,段落内是一段不换行的文本,但是不同格式的会被分开存储到不同的run也就是存到不同段落片段中)来存储替换的文本,然后将其插入到段落中。然而,创建的新运行元素可能不会保留原始段落中的格式设置,这可能导致格式变化。
解决方法:复制段落原本的格式设置给要插入进去的run
/**
* 替换书签内文本
* @param document
* @param bookTagMap key: 书签名 value :需要替换书签的新文本
*/
public static void replaceBookmarkText(XWPFDocument document, Map<String, String> bookTagMap) {
List<XWPFParagraph> paragraphList = document.getParagraphs();
for (XWPFParagraph xwpfParagraph : paragraphList) {
CTP ctp = xwpfParagraph.getCTP();
for (int dwI = 0; dwI < ctp.sizeOfBookmarkStartArray(); dwI++) {
CTBookmark bookmark = ctp.getBookmarkStartArray(dwI);
if (bookTagMap.containsKey(bookmark.getName())) {
XWPFRun run = xwpfParagraph.createRun();
// 获取书签所在段落内的所有运行元素
List<XWPFRun> runs = xwpfParagraph.getRuns();
// 从书签范围内的运行元素中选择一个样式
XWPFRun originalRun = null;
for (XWPFRun xwpfRun : runs) {
if (xwpfRun.getCTR().getDomNode() == bookmark.getDomNode()) {
originalRun = xwpfRun;
break;
}
}
// 如果未找到匹配的运行元素,则使用段落内的第一个运行元素的样式
if (originalRun == null && !runs.isEmpty()) {
originalRun = runs.get(0);
}
if (originalRun != null) {
run.getCTR().setRPr(originalRun.getCTR().getRPr());
}
run.setText(bookTagMap.get(bookmark.getName()).toString());
Node firstNode = bookmark.getDomNode();
Node nextNode = firstNode.getNextSibling();
while (nextNode != null) {
String nodeName = nextNode.getNodeName();
if (nodeName.equals("w:bookmarkEnd")) {
break;
}
Node delNode = nextNode;
nextNode = nextNode.getNextSibling();
ctp.getDomNode().removeChild(delNode);
}
if (nextNode == null) {
ctp.getDomNode().insertBefore(run.getCTR().getDomNode(), firstNode);
} else {
ctp.getDomNode().insertBefore(run.getCTR().getDomNode(), nextNode);
}
}
}
}
}
遗留问题:
在一个书签或占位符内插入多个段落并保持源格式的问题!
首先占位符本身在word内就是单独占一个段落。但是我要将占位符替换成这三个段落进去。
这个问题小编也还没找到解决方案,希望各位大佬有方案告知小编学习一下。
看到这里了都,最后希望各位老板动动小手点点赞,喜欢小编分享内容可以点个小小关注噢,再次感谢!