本文非原创,只是整理了下代码,原代码出自:http://blog.chiefleo.me/archives/429.原文如下:
普通的读取批注信息方法:
public void readWordDocxComments(String fileName) { XWPFDocument document = null; XWPFComment[] comments = null; try { document = new XWPFDocument(POIXMLDocument.openPackage(fileName)); comments = document.getComments(); for (int i = 0; i < comments.length; i++) { System.out.println("Id= " + comments[i].getId()); System.out.println("Text= " + comments[i].getText()); System.out.println("Author= " + comments[i].getAuthor()); } } catch (Exception e) { e.printStackTrace(); } }
不能获取批注对应的正文信息,修改后的代码如下:
import java.io.File; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.poi.POIXMLDocument; import org.apache.poi.POIXMLDocumentPart; import org.apache.poi.xwpf.usermodel.XWPFComment; import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFRelation; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTComment; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CommentsDocument; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CommentsDocument.Factory; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public class POI_读取批注_S4_Test { private File file; /** Word document */ private XWPFDocument docx; /** 批注内容数组 */ private XWPFComment[] comments;// /** 批注引用正文map,结构-<批注Id,正文text> */ private Map<String, String> commentRefs;// /** 日期格式化类型 */ private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); /** 批注所引用正文装配Map完毕标识 */ private static final String COMMENT_REF_FILLED_OK = "OK"; /** 批注最大下标 */ private String maxCommentIndex; /* * @param filePath Word文件路径 */ public POI_读取批注_S4_Test(String filePath) throws Exception { file = new File(filePath); initAttributes(); } /* * 初始化成员变量 * @throws Exception Word缺陷导入异常 */ private void initAttributes() throws Exception { try { docx = new XWPFDocument(POIXMLDocument.openPackage(file .getCanonicalPath())); comments = docx.getComments(); maxCommentIndex = String.valueOf(comments.length - 1); commentRefs = new HashMap<String, String>(); fillCommentRef(docx.getDocument().getDomNode(), new StringBuilder(), new StringBuilder(), new StringBuilder(), commentRefs); } catch (Exception e) { throw new Exception(new StringBuilder().append("Word文件格式错误") .append("-").append(e.getMessage()).toString(), e); } } /* * 获取批注内容 */ public XWPFComment[] getComments() { return comments; } public Map<String, String> getCommentRefs() { return commentRefs; } /* * 获取日期格式化类型 */ public SimpleDateFormat getSdf() { return sdf; } /* 获取批注日期List */ public List<Date> getSubmitDateList() { Map<String, Date> dateMap = new HashMap<String, Date>(); List<Date> dateList = new ArrayList<Date>(); try { Iterator<POIXMLDocumentPart> iter = docx.getRelations().iterator(); do { if (!iter.hasNext()) break; POIXMLDocumentPart p = (POIXMLDocumentPart) iter.next(); String relation = p.getPackageRelationship() .getRelationshipType(); if (relation.equals(XWPFRelation.COMMENT.getRelation())) { CommentsDocument cmntdoc; cmntdoc = Factory .parse(p.getPackagePart().getInputStream()); List<CTComment> commentList = cmntdoc.getComments() .getCommentList(); int len = commentList.size(); int j = 0; while (j < len) { CTComment ctcomment = commentList.get(j); dateMap.put(ctcomment.getId().toString(), ctcomment .getDate().getTime()); j++; } } } while (true); } catch (Exception e) { } if (dateMap != null) { for (XWPFComment comment : comments) { dateList.add(dateMap.get(comment.getId())); } } return dateList; } /* * 获取批注作者List */ public List<String> getSubmitterList() { List<String> list = new ArrayList<String>(); for (XWPFComment comment : comments) { list.add(comment.getAuthor().trim()); } return list; } /* * 组装批注引用文本Map,Map结构-<commentId,text> * @param node WordProcessingML node * @param id 批注ID * @param value 批注引用正文文本 * @param convertOK 正文组装完毕标识 ,组装完毕 = "OK" * @param map 要填充的目标Map */ private void fillCommentRef(Node node, StringBuilder id, StringBuilder value, StringBuilder convertOK, Map<String, String> map) throws Exception { // fillCommentRef方法要求所有参数不能为null,如果为null,抛出异常 if (!insureNotNull(node, id, value, convertOK, map)) { throw new IllegalArgumentException(new StringBuilder() .append(this.getClass().getName()) .append("fillCommentRef(").append(node).append(",") .append(id).append(",").append(value).append(",") .append(convertOK).append(",").append(map).append(")") .toString()); } /* * docx文件批注所引用的正文保存在document.xml中,可以通过重命名xx.docx为xx.zip来查看 * 其中如果某段正文文本内容有批注,那么会在document.xml这样保存 <w:commentRangeStart w:id="0" /> * <w:t>正文文本</w:t> </w:r> <w:commentRangeEnd w:id="0" /> * 如果被批注的是在图片上加批注,那么会在document * .xml中这样保存(仅限真正docx文件,如果是doc文件另存为docx文件,<wp:docPr节点中是没有属性的) * <w:commentRangeStart w:id="1" /> <wp:docPr id="1" name="xxx" * descr="yyy.png" /> <w:commentRangeEnd w:id="1" /> * * 1)id初始值为空,如果解析到节点w:commentRangeStart,就代表是有批注的部分,需要把参数id设为节点的id属性值 * 2)顺次解析下面节点 * ,如果此时的id不为空,就代表进入批注引用部分,w:t是文本内容,直接append;wp:docPr是图片内容,用"[xxx]" * 来区分是图片,然后append. * 3)如果解析到节点w:commentRangeEnd,就代表一个批注引用完毕,这时需要向Map中put(id,value)值; * 判断当前的批注Id是不是最大 * ,如果为最大批注Id,convertOK置为"OK",用此标识来说明批注引用提取完毕,退出节点for循环?例如一个很大的Word文件 * ,只在第2页做了一个批注,前面的做法会很有用; * 同时还要做好一条批注引用解析完毕的收尾工作:id清空,代表下面节点又是无批注的部分;value清空,待下次新的批注append. */ if ("w:t".equals(node.getNodeName()) && id.length() > 0) { value.append(node.getFirstChild().getNodeValue()); } else if ("wp:docPr".equals(node.getNodeName()) && id.length() > 0) { value.append("[").append(getAttribute(node, "name")).append("]"); } else if ("w:commentRangeStart".equals(node.getNodeName())) { id.setLength(0); id.append(getAttribute(node, "w:id")); value.setLength(0); } else if ("w:commentRangeEnd".equals(node.getNodeName()) && id.length() > 0) { if (id.toString().equals(getAttribute(node, "w:id"))) { map.put(id.toString(), value.toString()); if (id.toString().equals(maxCommentIndex)) { convertOK.setLength(0); convertOK.append(COMMENT_REF_FILLED_OK); id.setLength(0); value.setLength(0); } } } if (node.hasChildNodes()) { NodeList temp = node.getChildNodes(); for (int i = 0; i < temp.getLength(); i++) { if (convertOK.toString().endsWith(COMMENT_REF_FILLED_OK)) { break; } fillCommentRef(temp.item(i), id, value, convertOK, map); } } } /*** * @param node * 当前的Node * @param attName * 要获取的属性名 * @return 属性值,没有该属性时返回null */ private static String getAttribute(Node node, String attName) { return (node.hasAttributes() && node.getAttributes().getNamedItem( attName) != null) ? node.getAttributes().getNamedItem(attName) .getNodeValue() : null; } /* * 确保此方法的所有参数均不为空 * @param objects 对象参数 * @return 所有参数均不为空返回true 否则为false */ private boolean insureNotNull(Object... objects) { for (Object object : objects) { if (object == null) { return false; } } return true; } public static void main(String[] args) throws Exception { StringBuffer value = new StringBuffer(); POI_读取批注_S4_Test wh = new POI_读取批注_S4_Test( "f:/saveFile/temp/sys_comment_07.docx"); XWPFComment[] comments = wh.getComments(); Map<String, String> commenRefMap = wh.getCommentRefs(); List<Date> l = wh.getSubmitDateList(); SimpleDateFormat sdf = wh.getSdf(); XWPFComment comment; for (int i = 0; i < comments.length; i++) { comment = comments[i]; value.append("批注Id:").append(comment.getId()).append(", ") .append("批注作者:").append(comment.getAuthor()).append(", ") .append("批注日期:").append(sdf.format(l.get(i))).append(", ") .append("批注内容:").append(comment.getText()).append(", ") .append("批注引用正文:") .append(commenRefMap.get(comment.getId())); value.append("\n"); } System.out.println(value); } }
结果为:
全文完。
相关推荐
首先,让我们了解如何通过Java POI读取Word文档。在Java中,我们需要导入`org.apache.poi.xwpf.usermodel`包,因为这个包包含了处理`.docx`文件所需的类。`.docx`是Word 2007及更高版本使用的XML格式。以下是一个...
在Java编程环境中,读取Word 2003文档是一项常见的任务,这通常涉及到处理`.doc`文件格式。为了实现这个功能,开发者可以利用各种库,如Apache POI或者JODConverter。Apache POI是一个流行的开源项目,它提供了对...
Java 使用 POI 合并两个 Word 文档 Java 是一种流行的编程语言,POI(Poor Obfuscation Implementation)是一个流行的 Java 库,用于操作 Microsoft Office 文件,包括 Word 文档。合并两个 Word 文档是指将两个...
使用aspose.words,获取word文件中的标题,批注,批注所在标题,标题序号,在书签处插入图片,在指定文字处插入图片等
为了实现文档预览,我们需要创建一个Controller,该Controller接收前端请求,读取服务器上的PDF、Word或Excel文件,然后将文件内容转换为适合在浏览器中展示的格式。 对于PDF文件,在Java Web环境中,可以使用...
5. **批注和注释**:POI提供了处理Excel批注和Word注释的功能,可以读取、添加和修改这些元数据。 6. **事件模型**:为处理大型文件,POI提供了事件模型(SXSSF),这是一种基于内存优化的低级别API,可以避免加载...
- 兼容性:除了基本的读写功能,POI还支持解析和生成复杂的公式、图表、超链接、批注等。 - 错误处理:提供完善的异常处理机制,帮助开发者定位和解决问题。 8. **示例代码**: - 创建一个新的Excel文件并写入...
Java POI是一个强大的库,由Apache软件基金会开发,专门用于处理Microsoft Office格式的文件,特别是Excel、Word和PowerPoint文档。在Java世界中,如果你需要读取、创建或修改Excel电子表格,Java POI就是不可或缺的...
Java 获取 Word 中的所有插入和删除修订 在 Word 文档中启用跟踪更改功能后,会记录文档中的所有编辑行为,例如插入、删除、替换和格式更改。这篇文章将介绍如何使用 Java 获取 Word 文档中的所有插入和删除修订。 ...
"标签"中的"java"表明了编程语言,"导出word批注"指出了主要功能,而"poi"则明确表示了使用的技术栈。Apache POI库提供了一系列接口,比如HWPF(用于处理老版本的DOC文件)和XWPF(用于处理新版本的DOCX文件),来...
例如,读取Excel文件可以用`XSSFWorkbook`,读取Word文件用`XWPFDocument`,读取PowerPoint文件用`XMLSlideShow`。 3. **转换为HTML**:为了在线预览,需要将文档内容转换为HTML格式。这通常涉及到解析Office文档的...
值得注意的是,为了确保转换的纯净性,用户被建议在转换前删除Word文档中的批注。 这个小工具的实现可能基于对Microsoft Office接口的调用,或者使用了专门的文档转换库,例如Apache POI for .NET或其他第三方库。...
3. **Java的Apache POI**:支持处理Word、Excel和PowerPoint的OOXML文件。 **应用场景** - 自动化文档生成:编程生成报告、合同或其他格式化的文本。 - 数据提取:从大量Excel文件中提取数据进行分析。 - 文档转换...
它还详细解释了PageOffice在OA系统中实现文档在线编辑及流转痕迹保留、键盘批注、手写批注等高级功能的方法。这些功能的实现依赖于PageOffice如何与数据库交互,并且教程解释了SaveDataPage和SaveFilePage这两个关键...
随着项目的发展,NPOI可能会考虑自研对Word文档的支持,以弥补Java POI中HWPF的不足。 总之,NPOI是.NET开发者处理Excel文件的强大工具,提供了丰富的API来创建、读取和修改Excel内容,同时支持各种复杂的格式设置...
8. **批注和超链接**:NPOI允许你在单元格中添加批注,或者为单元格设置超链接,以增强信息的交互性。 9. **性能优化**:NPOI采用流式处理,对于大数据量的文件,可以减少内存占用,提高处理效率。 10. **兼容性**...
5. 文件处理:使用Apache POI或JavaFX的文件处理API,处理上传的Word文档或其他格式的作业。 三、系统架构 1. 用户模块:包含教师和学生的账号管理,登录验证,权限控制等功能。 2. 作业管理模块:教师可以发布作业...
**NPOI** 是一个基于 Apache POI 的 .NET 库,用于在没有安装 Microsoft Office 的情况下读写 Office 文件。它最初是为了满足 .NET 开发者在 C# 和其他 .NET 语言中处理 Excel 文件的需求而开发的。NPOI 目前支持 ...