問題描述
如何從 docxtemplater.js 輸出 docx 以在 jszip 中輸入 (How can I output a docx from docxtemplater.js for input in jszip)
使用 jszip 和 docxtemplater 我正在嘗試將多個 docx 文檔添加到 zip 存檔中,但我失敗了。我的存檔只包含不可讀的 0 字節 docx 文件。
我想我不明白如何將二進制模式的 docx 文件添加到存檔中。我添加了從上面提到的示例中融合而來的相當長的示例代碼。
你能告訴我如何修改 generate() 函數的輸出或將文件添加到 zip ‑存檔?
<html>
<body>
<button onclick="zip_docx()">Generate document</button>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/docxtemplater/3.17.9/docxtemplater.js"></script>
<script src="https://unpkg.com/pizzip@3.0.6/dist/pizzip.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.8/FileSaver.js"></script>
<script src="https://unpkg.com/pizzip@3.0.6/dist/pizzip‑utils.js"></script>
<script src="jszip.min.js"></script>
<!‑‑
Mandatory in IE 6, 7, 8 and 9.
‑‑>
<!‑‑[if IE]>
<script type="text/javascript" src="https://unpkg.com/pizzip@3.0.6/dist/pizzip‑utils‑ie.js"></script>
<![endif]‑‑>
<script>
function loadFile(url,callback){
PizZipUtils.getBinaryContent(url,callback);
}
function zip_docx(){
var zip = new JSZip();
var file1 = generate("file1");
var file2 = generate("file2");
var file3 = generate("file3");
zip.file("file1.docx", file1);
zip.file("file2.docx", file2);
zip.file("file3.docx", file3);
zip.generateAsync({type:"blob"})
.then(function(content) {
// see FileSaver.js
saveAs(content, "example.zip");
});
}
function generate() {
loadFile("https://docxtemplater.com/tag‑example.docx",function(error,content){
if (error) { throw error };
// The error object contains additional information when logged with JSON.stringify (it contains a properties object containing all suberrors).
function replaceErrors(key, value) {
if (value instanceof Error) {
return Object.getOwnPropertyNames(value).reduce(function(error, key) {
error[key] = value[key];
return error;
}, {});
}
return value;
}
function errorHandler(error) {
console.log(JSON.stringify({error: error}, replaceErrors));
if (error.properties && error.properties.errors instanceof Array) {
const errorMessages = error.properties.errors.map(function (error) {
return error.properties.explanation;
}).join("\n");
console.log('errorMessages', errorMessages);
// errorMessages is a humanly readable message looking like this :
// 'The tag beginning with "foobar" is unopened'
}
throw error;
}
var zip = new PizZip(content);
var doc;
try {
doc=new window.docxtemplater(zip);
} catch(error) {
// Catch compilation errors (errors caused by the compilation of the template : misplaced tags)
errorHandler(error);
}
doc.setData({
first_name: 'John',
last_name: 'Doe',
phone: '0652455478',
description: 'New Website'
});
try {
// render the document (replace all occurences of {first_name} by John, {last_name} by Doe, ...)
doc.render();
}
catch (error) {
// Catch rendering errors (errors relating to the rendering of the template : angularParser throws an error)
errorHandler(error);
}
var out=doc.getZip().generate({
type:"blob",
mimeType: "application/vnd.openxmlformats‑officedocument.wordprocessingml.document",
}) //Output the document using Data‑URI
//saveAs(out,"output.docx")
return out
})
}
</script>
</code></pre>
參考解法
方法 1:
After researching the comment of muellermarkus, I was consulting with the leader of the project and I opened an issue on github. There is an answer there which I copy here as a reference. The main hurdle was the addition of {base64: true} as option when the docx‑file is added to the archive.
<html lang="en">
<body>
<button onclick="generate()">Generate document</button>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/docxtemplater/3.17.9/docxtemplater.js"></script>
<script src="https://unpkg.com/pizzip@3.0.6/dist/pizzip.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.8/FileSaver.js"></script>
<script src="https://unpkg.com/pizzip@3.0.6/dist/pizzip‑utils.js"></script>
<script>
var zipDocs = new PizZip();
function loadFile(url,callback){
PizZipUtils.getBinaryContent(url,callback);
}
function generate() {
loadFile("https://docxtemplater.com/tag‑example.docx",function(error,content){
if (error) { throw error };
// The error object contains additional information when logged with JSON.stringify (it contains a properties object containing all suberrors).
function replaceErrors(key, value) {
if (value instanceof Error) {
return Object.getOwnPropertyNames(value).reduce(function(error, key) {
error[key] = value[key];
return error;
}, {});
}
return value;
}
function errorHandler(error) {
console.log(JSON.stringify({error: error}, replaceErrors));
if (error.properties && error.properties.errors instanceof Array) {
const errorMessages = error.properties.errors.map(function (error) {
return error.properties.explanation;
}).join("\n");
console.log('errorMessages', errorMessages);
// errorMessages is a humanly readable message looking like this :
// 'The tag beginning with "foobar" is unopened'
}
throw error;
}
const array = ['John','Jane']
array.forEach(function(name){
var zip = new PizZip(content);
var doc;
try {
doc=new window.docxtemplater(zip);
} catch(error) {
// Catch compilation errors (errors caused by the compilation of the template : misplaced tags)
errorHandler(error);
}
console.log(name);
doc.setData({
first_name: name,
last_name: 'Doe',
phone: '0652455478',
description: 'New Website'
});
try {
// render the document (replace all occurences of {first_name} by John, {last_name} by Doe, ...)
doc.render();
}
catch (error) {
// Catch rendering errors (errors relating to the rendering of the template : angularParser throws an error)
errorHandler(error);
}
var out=doc.getZip().generate() //Output the document using Data‑URI
zipDocs.file(name+".docx", out, {base64: true});
console.log(name, " wurde gezippt.");
})
var content = zipDocs.generate({ type: "blob" });
// see FileSaver.js
saveAs(content, "example.zip");
})
}
</script>
方法 2:
It worked for me (with Angular)
HTML
<input type="file" placeholder="Upload docx template" #docx>
<hr>
<button (click)="readDocxFile(docx)">Save</button>
Function on Component
readDocxFile(elm: any): void {
const reader = new FileReader();
if (elm.files.length === 0) {
console.log('No files selected');
}
reader.readAsBinaryString(elm.files.item(0));
reader.onerror = (event) => {
console.log('error reading file', event);
};
reader.onload = (event) => {
const content = event.target.result;
const zip = new PizZip(content);
this.filesService.save(zip, this.data);
};
}
My service
import { Injectable } from '@angular/core';
import * as JSZip from 'JSZip';
import { saveAs } from 'file‑saver';
declare const docxtemplater: any;
@Injectable({
providedIn: 'root',
})
export class SaveFilesService {
constructor() {}
save(zipContent: any, data: any[]): void {
const zip = new JSZip();
data.forEach((val) => {
const file = this.generate(zipContent, val);
zip.file(`Word_${val.docNr}.docx`, file);
});
zip.generateAsync({ type: 'blob' }).then((content) => {
saveAs(content, 'example.zip');
});
}
generate(zip: any, val: any): any {
const doc = new docxtemplater(zip).setData(val).render();
const out = doc.getZip().generate({
type: 'blob',
mimeType:
'application/vnd.openxmlformats‑officedocument.wordprocessingml.document',
});
return out;
}
}
(by timm、timm、Vasile Radeanu)
參考文件