Apache POI:如何提取批注对应的高亮选中文本?
提取Word文档批注及对应高亮选中文本(Apache POI实现)
你当前的代码已经能成功提取批注内容,但要获取批注对应的高亮选中文本,需要利用Word文档中CommentRangeStart和CommentRangeEnd的配对关系——这两个标记分别定义了批注覆盖文本的起始和结束位置,且二者拥有相同的ID。
下面是修改后的代码,实现同时提取批注文本和对应的高亮选中文本:
import org.apache.poi.xwpf.usermodel.*; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTMarkupRange; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR; import java.io.FileInputStream; import java.util.HashMap; import java.util.List; import java.util.Map; public class CommentExtractor { public static void main(String[] args) throws Exception { String fileName = "test.docx"; FileInputStream fis = new FileInputStream(fileName); XWPFDocument xdoc = new XWPFDocument(OPCPackage.open(fis)); // 先收集所有段落中的CommentRangeEnd,按ID存储 Map<String, CTMarkupRange> endMarkupMap = new HashMap<>(); for (XWPFParagraph p : xdoc.getParagraphs()) { List<CTMarkupRange> endMarkups = p.getCTP().getCommentRangeEndList(); for (CTMarkupRange endMarkup : endMarkups) { endMarkupMap.put(endMarkup.getId().toString(), endMarkup); } } // 遍历段落处理CommentRangeStart,匹配对应End并提取文本 for (XWPFParagraph p : xdoc.getParagraphs()) { List<CTMarkupRange> startMarkups = p.getCTP().getCommentRangeStartList(); for (CTMarkupRange startMarkup : startMarkups) { String commentId = startMarkup.getId().toString(); XWPFComment comment = xdoc.getCommentByID(commentId); CTMarkupRange endMarkup = endMarkupMap.get(commentId); if (endMarkup != null) { // 提取当前段落中Start和End之间的文本 StringBuilder highlightedText = new StringBuilder(); List<CTR> runs = p.getCTP().getRList(); boolean isInRange = false; for (CTR run : runs) { // 检查当前run是否进入批注范围 if (run.getCommentRangeStartList().stream().anyMatch(s -> s.getId().equals(startMarkup.getId()))) { isInRange = true; } if (isInRange) { highlightedText.append(run.xmlText().replaceAll("<[^>]+>", "")); // 提取纯文本 } // 检查当前run是否离开批注范围 if (run.getCommentRangeEndList().stream().anyMatch(e -> e.getId().equals(endMarkup.getId()))) { isInRange = false; break; } } // 输出结果 System.out.println("批注内容:" + comment.getText()); System.out.println("对应高亮文本:" + highlightedText.toString().trim()); System.out.println("------------------------"); } } } xdoc.close(); fis.close(); } }
关键说明
- ID配对逻辑:每个批注的起始和结束标记共享同一个ID,通过Map提前存储所有结束标记,可快速匹配对应范围
- 文本范围提取:遍历段落中的文本Run(CTR),判断当前Run是否处于批注标记的起止区间内,收集这段范围内的文本
- 跨段落扩展:上述代码仅处理同段落内的批注文本,如果批注跨多个段落,需要额外遍历后续段落,直到找到对应的
CommentRangeEnd标记,可基于现有逻辑扩展实现
内容的提问来源于stack exchange,提问作者ccudmore
相关产品推荐
相关产品推荐

