Introduction
In this project, I am sharing my Apps Script solution to merge multiple Google Docs into one single file. You can make a copy of the Google Sheet app to use it or take my script and use it in your own Apps Script project.
Demo
Here is the demo app in Google Sheet. In the input table where you can select the Google Docs on your Google Drive. Once you have the docs selected, then you can run the script button “Merge” to do the job for you. You can point to a folder for the merged doc and you can keep the page breaks between the selected docs if you want.
Core Function: mergeDocs_
Here is the core function which can take a list of doc urls or ids to merge, simple copy and paste into your project to use it.
/**
* @param {string[]} urlsOrIds a list of Google Docs urls or ids
* @param {boolean} keepPagebreak Insert a pagebreak between docs to be merged
* @param {string} filename The file name of the merged file
* @return {GoogleAppsScript.Drive.File} a merged Google Docs file
*/
const mergeDocs_ = (urlsOrIds, keepPagebreak = true, filename) => {
const urlFilter = (v) => v.startsWith("https://");
/**
* @param {GoogleAppsScript.Document.Document} targetDoc
* @param {boolean} keepPagebreak Insert a pagebreak between docs to be merged
* @param {GoogleAppsScript.Document.Document} doc
*/
const appendDoc_ = (targetDoc, doc, keepPagebreak = true) => {
const bodyTarget = targetDoc.getBody();
const body = doc.getBody();
const countOfElement = body.getNumChildren();
if (countOfElement === 0) return;
keepPagebreak && bodyTarget.appendPageBreak();
for (let i = 0; i < countOfElement; i++) {
const child = body.getChild(i);
const type = child.getType();
const copy = child.copy();
if (type === DocumentApp.ElementType.TABLE) {
bodyTarget.appendTable(copy.asTable());
} else if (type === DocumentApp.ElementType.PAGE_BREAK) {
bodyTarget.appendPageBreak(copy.asPageBreak());
} else if (type === DocumentApp.ElementType.INLINE_IMAGE) {
bodyTarget.appendImage(copy.asInlineImage());
} else if (type === DocumentApp.ElementType.HORIZONTAL_RULE) {
bodyTarget.appendHorizontalRule();
} else if (type === DocumentApp.ElementType.LIST_ITEM) {
const listItem = copy.asListItem();
bodyTarget
.appendListItem(listItem)
.setAttributes(listItem.getAttributes());
} else {
bodyTarget.appendParagraph(copy.asParagraph());
}
}
return targetDoc;
};
const [firstDoc, ...restDocs] = urlsOrIds
.map((v) => {
try {
return urlFilter(v)
? DocumentApp.openByUrl(v)
: DocumentApp.openById(v);
} catch (err) {
return err.message;
}
})
.filter((v) => typeof v !== "string");
filename = filename || "Merged doc " + new Date().toLocaleString();
const copy = DriveApp.getFileById(firstDoc.getId())
.makeCopy()
.setName(filename);
const mergedDoc = DocumentApp.openById(copy.getId());
restDocs.forEach((doc) => appendDoc_(mergedDoc, doc, keepPagebreak));
mergedDoc.saveAndClose();
return copy;
};
Deployment
Make a copy of my project from this link.