当前位置:   article > 正文

Java使用POI在word文档中替换书签或占位符内容_java替换word占位符并保留其格式

java替换word占位符并保留其格式

1.获取word文档对象

        写出两种不同获取word文档对象方式,通过文件服务器路径,和文件流的方式,请自行参考!

  1. /**
  2. * 根据文档服务器路径获取文档对象
  3. * @param wordPath
  4. * @return
  5. */
  6. public static XWPFDocument getXWPFDocument(String wordPath) {
  7. FileInputStream fis = null;
  8. XWPFDocument document = null;
  9. try {
  10. fis = new FileInputStream(new File(wordPath));
  11. document = new XWPFDocument(fis);
  12. } catch (Exception e) {
  13. throw new RuntimeException(e.getMessage());
  14. } finally {
  15. if (fis != null) {
  16. try {
  17. fis.close();
  18. } catch (Exception e) {
  19. throw new RuntimeException(e.getMessage());
  20. }
  21. }
  22. }
  23. return document;
  24. }
  25. /**
  26. * 根据文联流获取文档对象
  27. * @param inputStream
  28. * @return
  29. */
  30. public static XWPFDocument getXWPFDocument(InputStream inputStream) {
  31. XWPFDocument document = null;
  32. try {
  33. document = new XWPFDocument(inputStream);
  34. } catch (Exception e) {
  35. throw new RuntimeException(e.getMessage());
  36. } finally {
  37. if (inputStream != null) {
  38. try {
  39. inputStream.close();
  40. } catch (Exception e) {
  41. throw new RuntimeException(e.getMessage());
  42. }
  43. }
  44. }
  45. return document;
  46. }

2. 通过poi获取word内所有书签

       注意:_GoBack书签貌似是wps自带的隐藏书签,如果不剔除的话会多出这么个书签,并且表格部分书签和文字部分书签获取方法不同!

  1. /**
  2. * 获取word文档内所有书签
  3. *
  4. * @param document
  5. * @return
  6. */
  7. public static List<String> getBookMarksName(XWPFDocument document) {
  8. List<String> bookMarkList = new ArrayList<>();
  9. try {
  10. // 获取所有段落
  11. List<XWPFParagraph> paragraphs = document.getParagraphs();
  12. for (XWPFParagraph paragraph : paragraphs) {
  13. // 检查段落中是否有书签
  14. List<CTBookmark> bookmarks = paragraph.getCTP().getBookmarkStartList();
  15. for (CTBookmark bookmark : bookmarks) {
  16. if (!bookmark.getName().equals("_GoBack")) {
  17. bookMarkList.add(bookmark.getName());
  18. }
  19. }
  20. }
  21. // 获取所有表格
  22. List<XWPFTable> tables = document.getTables();
  23. for (XWPFTable table : tables) {
  24. // 处理表格中的段落
  25. List<XWPFTableRow> rows = table.getRows();
  26. for (XWPFTableRow row : rows) {
  27. List<XWPFTableCell> cells = row.getTableCells();
  28. for (XWPFTableCell cell : cells) {
  29. // 处理单元格中的段落
  30. List<XWPFParagraph> cellParagraphs = cell.getParagraphs();
  31. for (XWPFParagraph paragraph : cellParagraphs) {
  32. // 检查段落中是否有书签
  33. List<CTBookmark> bookmarks = paragraph.getCTP().getBookmarkStartList();
  34. for (CTBookmark bookmark : bookmarks) {
  35. if (!bookmark.getName().equals("_GoBack")) {
  36. bookMarkList.add(bookmark.getName());
  37. }
  38. }
  39. }
  40. }
  41. }
  42. }
  43. } catch (Exception e) {
  44. throw new RuntimeException(e.getMessage());
  45. }
  46. return bookMarkList;
  47. }

3.通过poi获取word内所有占位符

        只需通过文档对象加正则表达式即刻获取占位符,另外此处仅写出了对文本部分占位符获取,表格部分不适应噢;

  1. /**
  2. * 获取文档内所有占位符
  3. *
  4. * @param document 文档对象
  5. * @param regex 占位符正则表达式
  6. * @return
  7. */
  8. public static List<String> getPlaceholderName(XWPFDocument document, String regex) {
  9. List<String> matchedTextList = new ArrayList<>();
  10. for (XWPFParagraph paragraph : document.getParagraphs()) {
  11. String text = paragraph.getText();
  12. Pattern pattern = Pattern.compile(regex);
  13. Matcher matcher = pattern.matcher(text);
  14. while (matcher.find()) {
  15. matchedTextList.add(matcher.group());
  16. }
  17. }
  18. return matchedTextList;
  19. }

4.替换占位符处文本内容

问题:指定书签位置替换,插入文本信息,会删除不属于书签所在内容
原因:获取书签位置段落,存在书签只是段落其中的一个或者多个run,如果移除段落中的run,则会删除多余内容,无法达到预期效果
  1. /**
  2. * 替换占位符位置文本
  3. * @param document 文档对象
  4. * @param placeholder 占位符
  5. * @param replacementText 要替换占位符的新文本
  6. */
  7. public static XWPFDocument replacePlaceholder(XWPFDocument document, String placeholder, String replacementText) {
  8. for (XWPFParagraph paragraph : document.getParagraphs()) {
  9. StringBuilder paragraphText = new StringBuilder();
  10. // 遍历段落中的每个文本片段
  11. for (XWPFRun run : paragraph.getRuns()) {
  12. String text = run.getText(0);
  13. if (text != null) {
  14. paragraphText.append(text);
  15. }
  16. }
  17. // 获取段落中的文本
  18. String fullText = paragraphText.toString();
  19. // 寻找占位符位置
  20. int startIndex = fullText.indexOf(placeholder);
  21. boolean replaceText = false;
  22. while (startIndex >= 0) {
  23. // 定位到包含占位符的文本片段的位置
  24. int endIndex = startIndex + placeholder.length();
  25. // 替换占位符文本片段
  26. for (int i = 0; i < paragraph.getRuns().size(); i++) {
  27. XWPFRun run = paragraph.getRuns().get(i);
  28. String runText = run.getText(0);
  29. if (runText != null) {
  30. int runLength = runText.length();
  31. if (startIndex < runLength && placeholder.contains(runText) && replaceText == false) {
  32. replaceText = true;
  33. int relativeStartIndex = Math.max(startIndex, 0);
  34. int relativeEndIndex = Math.min(endIndex, runLength);
  35. String newText = runText.substring(0, relativeStartIndex) + replacementText + runText.substring(relativeEndIndex);
  36. run.setText(newText, 0);
  37. } else if (startIndex < runLength && placeholder.contains(runText) && replaceText){
  38. run.setText("", 0);
  39. }
  40. startIndex -= runLength;
  41. endIndex -= runLength;
  42. }
  43. }
  44. }
  45. }
  46. return document;
  47. }

5.替换书签部分文本内容

问题1:指定书签位置替换,插入文本信息,会删除不属于书签所在内容
原因:获取书签位置段落,存在书签只是段落其中的一个或者多个run,如果移除段落中的run,则会删除多余内容,无法达到预期效果
问题2:书签内容替换后,替换文本格式发生改变
原因:由于我是创建了一个新的运行元素 XWPFRun run = xwpfParagraph.createRun(); (run就是段落对象的下一层,段落内是一段不换行的文本,但是不同格式的会被分开存储到不同的run也就是存到不同段落片段中)来存储替换的文本,然后将其插入到段落中。然而,创建的新运行元素可能不会保留原始段落中的格式设置,这可能导致格式变化。
解决方法:复制段落原本的格式设置给要插入进去的run
  1. /**
  2. * 替换书签内文本
  3. * @param document
  4. * @param bookTagMap key: 书签名 value :需要替换书签的新文本
  5. */
  6. public static void replaceBookmarkText(XWPFDocument document, Map<String, String> bookTagMap) {
  7. List<XWPFParagraph> paragraphList = document.getParagraphs();
  8. for (XWPFParagraph xwpfParagraph : paragraphList) {
  9. CTP ctp = xwpfParagraph.getCTP();
  10. for (int dwI = 0; dwI < ctp.sizeOfBookmarkStartArray(); dwI++) {
  11. CTBookmark bookmark = ctp.getBookmarkStartArray(dwI);
  12. if (bookTagMap.containsKey(bookmark.getName())) {
  13. XWPFRun run = xwpfParagraph.createRun();
  14. // 获取书签所在段落内的所有运行元素
  15. List<XWPFRun> runs = xwpfParagraph.getRuns();
  16. // 从书签范围内的运行元素中选择一个样式
  17. XWPFRun originalRun = null;
  18. for (XWPFRun xwpfRun : runs) {
  19. if (xwpfRun.getCTR().getDomNode() == bookmark.getDomNode()) {
  20. originalRun = xwpfRun;
  21. break;
  22. }
  23. }
  24. // 如果未找到匹配的运行元素,则使用段落内的第一个运行元素的样式
  25. if (originalRun == null && !runs.isEmpty()) {
  26. originalRun = runs.get(0);
  27. }
  28. if (originalRun != null) {
  29. run.getCTR().setRPr(originalRun.getCTR().getRPr());
  30. }
  31. run.setText(bookTagMap.get(bookmark.getName()).toString());
  32. Node firstNode = bookmark.getDomNode();
  33. Node nextNode = firstNode.getNextSibling();
  34. while (nextNode != null) {
  35. String nodeName = nextNode.getNodeName();
  36. if (nodeName.equals("w:bookmarkEnd")) {
  37. break;
  38. }
  39. Node delNode = nextNode;
  40. nextNode = nextNode.getNextSibling();
  41. ctp.getDomNode().removeChild(delNode);
  42. }
  43. if (nextNode == null) {
  44. ctp.getDomNode().insertBefore(run.getCTR().getDomNode(), firstNode);
  45. } else {
  46. ctp.getDomNode().insertBefore(run.getCTR().getDomNode(), nextNode);
  47. }
  48. }
  49. }
  50. }
  51. }

遗留问题:

        在一个书签或占位符内插入多个段落并保持源格式的问题!

首先占位符本身在word内就是单独占一个段落。但是我要将占位符替换成这三个段落进去。

这个问题小编也还没找到解决方案,希望各位大佬有方案告知小编学习一下。

看到这里了都,最后希望各位老板动动小手点点赞,喜欢小编分享内容可以点个小小关注噢,再次感谢!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/天景科技苑/article/detail/829769
推荐阅读
相关标签
  

闽ICP备14008679号