Doc纯文本迁移到Doc表格中
前几日,一朋友给我发来了一个文档,说是让我帮忙把文本内容复制到一个新的表格内容中。当我做完第一份后,才知道还有很多文档需要处理。所以就想着做一个工具来批量处理。
踩坑记录
起初是这样想的:
- 先拿到文档的内容:因为给我的文档是
.doc
后缀的文件,然后通过一通readFile
操作,发现读出来一堆文字乱码。索性先停掉了这部分工作。 - 获取表格数据:最开始的想法是把表格转成
HTML
,然后通过设定模板的方法将内容导入。但是各种工具转成的HTML
都不尽人意,没样式、文字乱码。
然后发现两条路都堵死了,那不行啊。文档实在是太多了,难道真要一个一个的去复制吗?
又找了很久,发现了一个原本忽视的内容:.docx
文件,作为取代.doc
的格式,他的本质是一个 zip 文件。
[collapse title="详细信息"]
docx 是微软 Word 的文件扩展名,Microsoft Office2007 之后版本使用,其基于 Office Open XML 标准的压缩文件格式取代了其以前专有的默认文件格式,在传统的文件名扩展名后面添加了字母“x”(即“.docx”取代“.doc”、“.xlsx”取代“.xls”、“.pptx”取代“.ppt”)。任何能够打开 DOC 文件的文字处理软件都可以将该文档转换为 DOCX 文件,docx 文件比 doc 文件所占用空间更小,docx格式的文件本质上是一个XML文件
。
docx格式的文件本质上是一个ZIP文件
。将一个 docx 文件的后缀改为 ZIP 后是可以用解压工具打开或是解压的。事实上,Word2007 的基本文件就是 ZIP 格式的,他可以算作是 docx 文件的容器。
docx 格式文件的主要内容是保存为 XML 格式的,但文件并非直接保存于磁盘。它是保存在一个 ZIP 文件中,然后取扩展名为 docx。将 .docx 格式的文件后缀改为 ZIP 后解压, 可以看到解压出来的文件夹中有 word 这样一个文件夹,它包含了 Word 文档的大部分内容。而其中的document.xml
文件则包含了文档的主要文本内容。
百度百科-docx
[/collapse]
有了这个信息后,我觉得应该有希望了。第一步先被搁置了,我们从第二步开始。既然有了 xml 文件,那么就可以使用模板来进行 xml 的填充了。那就开始处理表格模板。
我们先把想要的字段都用标识字符进行占位(切记使用完整且准确的英文,不然会自动切割字符)
有了模板以后,通过 npm 包adm-zip
来直接解压表格模板数据。发现解压出来的document.xml
里面已经包含了之前定义的标识占位符。
那么填充就显得很简单了。通过readFile
读取到 xml 文件,然后替换的内容就完美填充到各个字段了。
到这里看起来后面的步骤已经完成了,但是第一步如何获取基础文档的内容呢。随后我在互联网的海洋中翻找了很久,找到了一个 npm 包@gmr-fms/word-extractor
。可以直接读取到 doc 文档内容(在此感谢大佬)
通过@gmr-fms/word-extractor
的支持,可以拿到整个文档,通过正则筛选出了我想要的字段内容,然后将内容替换给document.xml
。完成内容的更改。
最后一步就是将第二步解压出来的文档文件再压缩成一个.docx
文件,这里我使用的是archiver
,可以直接将文件压缩为.docx
。
代码实现
先装依赖
npm i @gmr-fms/word-extractor adm-zip archiver
const fs = require("fs");
const path = require("path");
// 读取doc文档工具
const extract = require("@gmr-fms/word-extractor");
// 直接解压docx文件
var admZip = require("adm-zip");
// 压缩文件
const archiver = require("archiver");
// 在doc文件夹下存放的是将要处理的文档
var files = fs.readdirSync(path.resolve(__dirname, "./doc"));
files.forEach((i) => {
var fileName = i.split("_")[0];
extract.fromFile(path.resolve(__dirname, "./doc/" + i)).then((doc) => {
var body = doc.getBody();
var number = body
.match(/第.*单元/g)[0]
.split("第")[1]
.split("单元")[0];
var name = body.match(/第.*课 .*/g)[0].split(" ")[1];
var time = body
.split("三、教学时间")[1]
.split("四、教学过程")[0]
.replace("\n", "")
.replace("\n", "");
var target = body.split("一、教学目标")[1].split("二、教学准备")[0].replace("\n", "");
var have = body.split("二、教学准备")[1].split("三、教学时间")[0].replace("\n", "");
var procedure = body.split("四、教学过程")[1].replace("\n", "");
// template下存放的是表格模板文件 index.docx 为表格模板
var zip = new admZip(`./template/index.docx`);
// result文件夹存放的是解压出来的表格模板文件夹
zip.extractAllTo(`./result/${fileName}`, true);
var xml = fs.readFileSync(`./result/${fileName}/word/document.xml`); // 读取document.xml
var xmlStr = xml.toString();
// 开始替换文档
xmlStr = xmlStr.replace(/number/g, number);
xmlStr = xmlStr.replace(/name/g, name);
xmlStr = xmlStr.replace(/time/g, time);
xmlStr = xmlStr.replace(/target/g, target);
xmlStr = xmlStr.replace(/have/g, have);
xmlStr = xmlStr.replace(/procedure/g, procedure);
// 重写文档
fs.writeFileSync(`./result/${name}/word/document.xml`, xmlStr);
var archive = archiver("zip", {
zlib: {
level: 8,
},
}).on("error", function (err) {
throw err;
});
// 压缩到 zip 文件夹下的是最终生成的带表格的文档
var output = fs.createWriteStream(__dirname + `/zip/${name}.docx`).on("close", function (err) {
if (err) {
console.log("关闭archiver异常:", err);
return;
}
console.log(`已生成${name}文件`);
});
archive.pipe(output);
archive.directory(`./result/${name}/`, "");
archive.finalize();
});
});
这里主要是提供了一个思路,供大家参考。合理的转变思路可能问题解决的会更方便点。
当前页面是本站的「Google AMP」版。查看和发表评论请点击:完整版 »