Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

前端玩Word:Word文档解析成浏览器认识的HTML #76

Open
CatsAndMice opened this issue Feb 20, 2024 · 0 comments
Open

前端玩Word:Word文档解析成浏览器认识的HTML #76

CatsAndMice opened this issue Feb 20, 2024 · 0 comments

Comments

@CatsAndMice
Copy link
Owner

前言

领导跟富文本编辑器杠上啦,领导有一个类似于某雀导入Word文档,解析内容后渲染到编辑器编辑的需求。某雀功能效果如下:

怎么搞定呢?自己写一个解析器?

本文分享Word文件转换成浏览器认识的HTML实战经验。

什么是Word文档

Word是微软公司开发的一个文字处理器应用程序,它是Office软件中的一个组件。使用Microsoft Office Word可创建和编辑信件、报告、网页或电子邮件中的文本和图形。相比于写字板和记事本功能更强大,性能更全面,可以插入图片、多媒体、艺术效果等

Word 支持的文件格式

列举一下Word常用的几种文件模式:

Word支持的文档格式蛮多,想了解的读者移步Word、Excel 和 PowerPoint 的文件格式参考

docx、doc有什么区别

Word文档格式相信读者跟我一样见过最多的是docx、doc格式。

有了doc为啥又带出个docx?

网上流传一个故事:从某一时期开始微软办公文件名的小尾巴多了一个“x”。原来word、PowerPoint还有excel,后缀名分别是doc、ppt、xls。后来,就突然涌现出了docx、pptx、xlsx。

原来的doc格式是加密的,只有微软自己家的软件才能打开。

后来微软觉得,这样并没有让自己很神圣,反而限制了自己的发展。

比如,金山WPS也是搞办公软件的,它的发展很快,积累了很多用户。不少人开始用wps了,word的用户面临被瓜分。于是,微软就基于Office Open XML标准,把文档家族做了兼容。

因为新标准是采用的xml格式记录信息的,所以就在.doc后面加了个x。新标准之后,即便是微软创建的文档,WPS也能打开。这样,用户只关心文档就行,不用在意用哪个软件,这就实现了用户共享。

当然我不能验证是否是真的,听说而已。

简单总结两者区别:

  • docx和doc相比文件体积更小,对复杂对象的处理也更好
  • docx是为了替代doc:Microsoft Word 2007版本开始,docx已经替代了doc,doc也不再进行开发
  • doc是二进制文件,docx是xml文件。docx扩展名可修改为zip、rar等压缩包格式,使用压缩软件打开,查看内部各类文件,实现批量替换图片等

Word文档转HTML实战

市面上实现该功能方案有两种:

  • 前端把Word文档上传给后端,由后端来解析,然后在通过接口把解析的内容返回给前端
  • 前端解析,直接把解析后的内容渲染出来或传递给后端

两种方案,说不上谁好谁坏,只有视业务场景来决定。

本文仅分享方案二的实现。想了解后端解析请移步Word转换HTML(Java实用版)

怎么来解析

docx看起来是一个文件,其实是一个压缩包,它的文件结构是这样的:

位于word下的document.xml文件docx的主文件。可以说,文档中你能看到的所有内容,在这里都有直接或者间接的记录。

document.xml内容都被XML标签进行了包裹,把XML标签转化成HTML标签即达成Word转HTML的目的。

前提是对XML标签熟悉,总不能瞎转吧!!!

不用担心,不熟悉也没关系,我们站在前人的肩膀上做这一步。

Mammoth是什么

Mammoth是一个专注于转换 .docx 文档的工具库,它能将Microsoft Word、Google Docs 和 LibreOffice 创建的文档转换成HTML,Mammoth会利用文档的XML语义信息,忽略其他细节,从而生成简单明了的 HTML。比如Mammoth会将任何带有标题 1 样式的段落转换为 h1 元素,但不会把标题的样式(字体、文字大小、颜色等)全部复制过去。

Mammoth支持以下功能:

  • 标题
  • 列表
  • 标题
  • 列表
  • 可定制的 docx 样式到 HTML 的映射。例如,您可以通过提供适当的样式映射,将 WarningHeading 转换为 h1.warning
  • 表格:表格格式(如边框)会被忽略
  • 脚注和尾注
  • 图片
  • 粗体、斜体、下划线、删除线、上标和下标。
  • 链接
  • 换行
  • 文本框:文本框的内容被视为一个单独的段落,出现在包含文本框的段落之后。
  • 注释

Mammoth提供了支持将docx转换成Markdown、HTML、纯文本的方法。

Mammoth实战

Mammoth官方demo:

const mammoth = require("mammoth");

mammoth.convertToHtml({path: "path/to/document.docx"})
    .then(function(result){
        const html = result.value; // 转换的HTML
        const messages = result.messages; 
    })
    .catch(function(error) {
        console.error(error);
    });

这是在Node.js环境中的案例,浏览器环境是无法通过{path: "path/to/document.docx"}来读取到docx文件。

如果是要在浏览器环境中执行它,需要docx文件转化为arrayBuffer数组再作为参数传递给convertToHtml

const  updateWord = {
	handleFileSelect(event) {
			const self = this
			this.readFileInputEventAsArrayBuffer(event, function (arrayBuffer) {
			    mammoth.convertToHtml({ arrayBuffer: arrayBuffer }, {
							//...
					})
			}
  },
	//文件转化成arrayBuffer数据类型
	readFileInputEventAsArrayBuffer(event, callback) {
      const file = event.target.files[0];
      const reader = new FileReader();
      reader.onload = function (loadEvent) {
          const arrayBuffer = loadEvent.target.result;
          callback(arrayBuffer);
      };
      reader.readAsArrayBuffer(file);
  }
}

//获取文件file后,传递给handleFileSelect函数
updateWord.handleFileSelect(file)

Word文档也许存在图片,Mammoth默认会把图片转成base64格式,这样我们得到的HTML内容会特殊的大。正常情况我们肯定是想要把图片上传到我们自己的服务器,HTML内容保留图片链接即可。

Mammoth也提供了相应方法:

const  updateWord = {
 //base64格式转blob
	base64ToBlob(base64, mimeType) {
        let bytes = window.atob(base64);
        let ab = new ArrayBuffer(bytes.length);
        let ia = new Uint8Array(ab);
        for (let i = 0; i < bytes.length; i++) {
            ia[i] = bytes.charCodeAt(i);
        }
        return new Blob([ia], { type: mimeType });
  },

	handleFileSelect(event,{success, fail}) {
			const self = this
			this.readFileInputEventAsArrayBuffer(event, function (arrayBuffer) {
			   mammoth.convertToHtml({ arrayBuffer: arrayBuffer }, {
                //处理图片
                convertImage: mammoth.images.imgElement(function (image) {
                    return image.read("base64").then(async (imageBuffer) => {
                        //base64转blob
                        const blob = self.base64ToBlob(imageBuffer, 'image/png')
                        blob.name = Date.now() + '.png'
                        const result = await new Promise((resolve, reject) => {
	                            //图片上传逻辑,可以自定义
															upImage({ file: blob }, {
                                resolve,
                                reject
                            })
                        })
                        const url = result.default
                        return {
                            src: url
                        }
                    });
                })
            }).then(success, fail);
			}
  },
//...
}

upImage是上传图片到我们自己服务器的逻辑,这个逻辑大家自定义发挥,只要最后把图片链接返回return {src: url},它会把base64替换掉。

至此,完成Word文档转换HTML,又能摸鱼了。

更高级的摸鱼

平常的学习、工作中,经常性出现某个项目开发上线某个功能,另外一个项目也提出相同的功能需求。历史总是惊人的相似。

为了以后再遇到类似需求,我把docx文件转换HTML这段代码保存在CodeGist中,方便下次直接引用。

CodeGist是一款代码管理工具,详细介绍请移步【工具推荐】代码管理工具 CodeGist

参考资源

推荐阅读

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant