一、了解word结构

文章:《Office文件格式基础知识》、《Anatomy of a WordProcessingML File》

office 97-03

office 97-03的存储规范为OLE。它是COM对象的子集,是一种对象链接和嵌入的技术,该技术可以包含文本,图形,电子表格甚至其他二进制数据。

OLE对象由对象头(ObjectHeader)和数据流(ObjectStream)组成。

(1)对象头各字段解析内容如下:

数据 解释
01050000 OLE Version
02000000 Format ID
09000000 ProgName Size(0x09)
4f4c45324c696e6b00 ProgName (OLE2Link)
000a0000 Data Size

(2)对象头和数据流通过d0cf11e0a1b11ae1分隔
(3)解析数据流的时候需要将ascii转换成hex

office 07-*

Doc文件的格式规范为OpenXML(OOXML),是微软在Office 2007中提出的一种新的文档格式。
Office 2007中的Word、Excel、PowerPoint默认均采用OpenXML格式。OpenXML在2006年12月成为了ECMA规范的一部分,编号为ECMA376;并于2008年4月通过国际标准化组织的表决,并于两个月后公布为ISO/IEC 29500国际标准。

Doc文件实际上一个压缩包,可以解压为目录。目录结构如下:

  • _rels文件夹:存放了所有指定的rels文件
  • docProps文件夹:存放了docx文档的主要属性信息
  • word文件夹:存放了docx文档的具体内容
  • [Content_Types].xml:描述的是整个文档内容的类型,把各个xml文件组合成一个整体

二、初步探索

  1. 新建word文档,输入一些内容(最好是有规律,易辨识的内容):正文、文本框、表格、在第二页再输入正文

  2. 修改word后缀为zip,解压缩后会发现文件格式确实如第一节中所述

  3. 打开每个xml文件,搜索在第1步输入的内容,寻找内容与xml的对应关系。

大致可以得出结论:word的主要内容存在word\document.xml中。如果只要解析正文中的内容,直接解析这个xml文件即可。

如果想页眉和页脚的文字内容,则需要另外解析word\header1.xmlword\foot1.xml等文件。

三、解析document.xml文件,读取doc中的文字

文字可能存在于正文(段落)、表格、文本框等位置。

正文(段落)中的文字直接读取XMLStreamConstants.CHARACTERS类型的内容即可获取。

但是如果文档中混合了表格和文本框的元素,则直接获取会出现以下问题:

  1. 表格会失去形状,表格中每个单元格的文本都会占一行
  2. 文本框中的文本会多次出现,原因是高版本的docx文件为了兼容低版本的word把文本框中的内容存了多份

问题1的解决方法:
根据结束标签的不同,执行不同的动作:

  • 正文中的段落结束标记:打印内容
  • 表格中单元格结束标记:追加\t
  • 表格中行结束标记:追加\n
  • 表格结束标记:打印内容

问题2的解决方法:

  1. 当遇到不希望解析的节点的开始标签时,开启屏蔽标记
  2. 开启屏蔽标记之后,不在收集内容节点
  3. 直到遇到该节点的结束标签时,关闭屏蔽标记

四、完整代码

import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Characters;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import java.io.*;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;/*** 解析word文档,打印出文件中的内容(目前只支持2010版word文件)* <p>* 支持正文(段落)、表格、文本框* <p>* 注:表格打印后仍然可以保持基本形状*/
public class ParseWord {/*** 是否开启调试*/private static boolean DEBUG = false;public static void main(String[] args) throws IOException {File docDir = unZipDocFiles("src/test.docx");parseDocumentXml(docDir);}/*** 解压doc文件到同目录下** @param docPath doc文件路径* @return 返回doc解压后的目录文件*/private static File unZipDocFiles(String docPath) throws IOException {String descDir = docPath.substring(0, docPath.lastIndexOf("."));return unZipFiles(docPath, descDir);}/*** 解压zip文件** @param zipPath zip文件路径* @param descDir 解压目录* @return 返回解压后的目录文件*/private static File unZipFiles(String zipPath, String descDir) throws IOException {ZipFile zip = new ZipFile(new File(zipPath), Charset.forName("GBK")); // 解决中文文件夹乱码File pathFile = new File(descDir);if (!pathFile.exists()) {pathFile.mkdirs();}for (Enumeration<? extends ZipEntry> entries = zip.entries(); entries.hasMoreElements(); ) {ZipEntry entry = (ZipEntry) entries.nextElement();String zipEntryName = entry.getName();InputStream in = zip.getInputStream(entry);String outPath = (descDir + "/" + zipEntryName);// 判断路径是否存在,不存在则创建文件路径File file = new File(outPath.substring(0, outPath.lastIndexOf('/')));if (!file.exists()) {file.mkdirs();}// 判断文件全路径是否为文件夹,如果是上面已经上传,不需要解压if (new File(outPath).isDirectory()) {continue;}FileOutputStream out = new FileOutputStream(outPath);byte[] buf1 = new byte[1024];int len;while ((len = in.read(buf1)) > 0) {out.write(buf1, 0, len);}in.close();out.close();}return pathFile;}/*** 解析document.xml** @param docDir doc解压后的目录文件*/private static void parseDocumentXml(File docDir) {try {String documentXmlPath = docDir.getPath() + "/word/document.xml";XMLInputFactory factory = XMLInputFactory.newInstance();XMLEventReader eventReader = factory.createXMLEventReader(new FileReader(documentXmlPath));// 屏蔽标记boolean maskFlag = false;// 表格内标记boolean inTable = false;StringBuffer s = new StringBuffer();while (eventReader.hasNext()) {XMLEvent event = eventReader.nextEvent();debug(event);switch (event.getEventType()) {case XMLStreamConstants.START_ELEMENT:StartElement startElement = event.asStartElement();if (isMarkLable(startElement.getName())) {// 屏蔽不想要的标签maskFlag = true;} else {if ("tbl".equals(startElement.getName().getLocalPart())) {// 当遇到tbl标签时表示进入表格inTable = true;}}break;case XMLStreamConstants.CHARACTERS:Characters characters = event.asCharacters();if (!maskFlag) {s.append(characters.getData());debug("==" + characters.getData());}break;case XMLStreamConstants.END_ELEMENT:EndElement endElement = event.asEndElement();if (!maskFlag) {switch (endElement.getName().getLocalPart()) {case "p":if (!inTable) {// 当p标签不在表格中时直接打印System.out.println(s);s = new StringBuffer();}break;case "tc":// 当遇到tc闭合标签时,表示表格中的单元格结束s.append("\t");break;case "tr":// 当遇到tc闭合标签时,表示表格中的行结束s.append("\n");break;case "tbl":// 当遇到tc闭合标签时,表示表格结束System.out.println(s);s = new StringBuffer();inTable = false;break;}}if (isMarkLable(endElement.getName())) {// 退出屏蔽标记maskFlag = false;}break;}}} catch (FileNotFoundException e) {e.printStackTrace();} catch (XMLStreamException e) {e.printStackTrace();}}//想要屏蔽的标签static Set<String> namespaceURIMarks = new HashSet<>();static {namespaceURIMarks.add("http://schemas.microsoft.com/office/word/2010/wordprocessingShape");namespaceURIMarks.add("http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing");namespaceURIMarks.add("http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing");}/*** 该标签是否需要屏蔽*/public static boolean isMarkLable(QName qName) {return namespaceURIMarks.contains(qName.getNamespaceURI());}/*** 用DEBUG变量来控制调试日志的输出*/private static void debug(Object s) {if (DEBUG) {System.out.println(s);}}}

输入:

输出:

解析word文件的简单实现相关推荐

  1. python table_用python解析word文件(二):table

    (二)表格篇(table)(本篇) 选你所需即可.下面开始正文. 上一篇我们讲了用python-docx解析docx文件中的段落,也就是paragraph,不过细心的同学可能发现了,只有自然段是可以用 ...

  2. java 解析xls 文件_java简单解析xls文件的方法示例【读取和写入】

    本文实例讲述了java简单解析xls文件的方法.分享给大家供大家参考,具体如下: 读取: import java.io.*; import jxl.*; import jxl.write.*; imp ...

  3. java如何解析word大纲_java解析word文件

    POI是Apache的一个开源项目,可以到Apache网站下载相应的jar包文件,及其源文件. POI提供了提取一些非TXT文本中文本内容的API,比如提取Word,Excel等,使用起来非常方便. ...

  4. 关于Endnote导入文献以及将参考文献插入到word文件的简单介绍

    关于Endnote导入文献的简单介绍 step1:打开百度学术,输入想要查找的文献名称或者相关关键字 step2: step3:选择endnote的文献引用格式 step4:选择参考文献引用格式 st ...

  5. php生成本地word文件怎么打开,php生成word文件的简单范例

    /** php生成word文件 link:bbs.it-home.org */ $word = new COM("word.application") or die("无 ...

  6. 用python解析word文件(三):style

    https://www.cnblogs.com/anpengapple/p/8372991.html 太长了,我决定还是拆开三篇写. (一)段落篇(paragraph) (二)表格篇(table) ( ...

  7. 应用python的docx模块解析word文件内容

    目录 工作问题 涉及知识点 实现过程 目标 调用对应的库和模块 定义通用方法 1.[遍历全部的同格式文件]返回一个文件夹内,限定某类格式文件,返回全部这类文件的绝对路径 2.[提取段落&表格中 ...

  8. 在Windows 7、8、10、11中恢复Word文件的简单方法

    "急急急!我使用快捷键"Shift + Delete"从我的电脑中删除了一些Word文件.但是我现在急需找回删除的Word文件,但我在回收站中找不到它们,并且我以前也没有 ...

  9. php 解析word文件,php解析word文档

    (twips) 官方网站: 首先解释一下 PHPWord 最基本的计量单位:"缇"(twips),我们常常 在文件中看到或使用计量单位"缇",它是开源办公软件中 ...

  10. java tika 解析pdf_Tika解析word文件

    Apache POI - HWPF and XWPF - Java API to Handle Microsoft Word Files 对Doc文件的解析 需要poi-scratchpad/3.7. ...

最新文章

  1. MySQL Sending data导致查询很慢的问题详细分析
  2. 平面广告设计和Web设计的差别
  3. cocos2dx 3.3 final 自定义事件 ---- EventListenerCustom
  4. 多个PHP版本环境搭建(nginx,php)
  5. Git reset , revert, checkout的区别和联系
  6. 操作系统原理第八章:内存管理
  7. netty权威指南学习笔记五——分隔符和定长解码器的应用
  8. Maven项目无法加载jdbc.properties
  9. Linux文本界面配置yum源,修改Linux默认语言 配置yum源
  10. Visual Studio 2017中找不到商业智能(Business Intelligence)模块 |
  11. 【100+ python基础入门-37】Python可变集合和不可变集合的构造方法和注意事项
  12. 论文笔记:A novel DRM scheme for accommodating expectations of personal use
  13. 从零到上亿用户,我是如何一步步优化MySQL数据库的?(建议收藏)
  14. 诛仙服务器状态查询,《诛仙3》部分服务器数据互通公告
  15. python蓝牙连接测试_基于python实现蓝牙通信代码实例
  16. safari浏览网页打开速度很慢怎样解决
  17. 2022Android笔试真题,20道高频面试题(含答案)
  18. mui框架scroll,鼠标滑轮可以滚动,移动端触摸无法滚动
  19. 基于requests+pyecharts的前程无忧工作岗位可视化分析
  20. 打开软件提示丢失vcruntime140.dll下载安装详细教程

热门文章

  1. java拦截器和过滤器的区别_拦截器和过滤器的区别
  2. 三线一控电动球阀、三线两控电动球阀、两线制断电开阀、两线制断电关阀四类电动球阀的区别
  3. 一个一键修改IP设置的BAT脚本
  4. 安卓投屏大师_【投屏】全平台全设备无线投屏工具幕享
  5. 测试工程师常见的算法面试题
  6. 读书笔记:深度学习入门-基于python的理论与实现(俗称鱼书)
  7. Unity3D 插件大全
  8. 计算机操作系统轮转算法代码,实验四 时间片轮转调度算法
  9. GAN详解与PyTorch MINIST手写数字生成实战
  10. 微信小程序视频+微信视频号视频下载教程