解析word文件的简单实现

(46) 2024-03-04 18:01:01

一、了解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文档,输入一些内容(最好是有规律,易辨识的内容):正文、文本框、表格、在第二页再输入正文
    解析word文件的简单实现 (https://mushiming.com/)  第1张

  2. 修改word后缀为zip,解压缩后会发现文件格式确实如第一节中所述
    解析word文件的简单实现 (https://mushiming.com/)  第2张
    解析word文件的简单实现 (https://mushiming.com/)  第3张

  3. 打开每个xml文件,搜索在第1步输入的内容,寻找内容与xml的对应关系。
    解析word文件的简单实现 (https://mushiming.com/)  第4张

大致可以得出结论: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 = 
THE END

发表回复