有没有办法保存 Google 文档,使其具有与现有文档相同的唯一 ID?

Is there a way of saving a Google Doc so it has the same unique ID as an existing doc?

我需要创建具有特定 ID 的 Google 文档的副本 - 不是像 MyDocument 这样的 "friendly" 名称,而是使其在GoogleSphere - 类似于 1x_tfTiA9-b5UwAf3k2fg6y6hyZSYQIvhSNn-saaDs4c 的那种。

以下是我想这样做的原因:

我有一份 Google 文档形式的时事通讯。通过将文档嵌入网页中的 <iframe> 元素内,将新闻通讯发布在网站上。同样以相同方式发布的是 "large print" 版本的时事通讯,除了默认字体大小为 24pt 而不是 11pt 之外。

我正在尝试自动化大字体版本的制作,但是大字体文档的唯一 ID 不会改变,所以它的嵌入式 <iframe> 仍然有效.

我过去曾尝试使用 Google Apps Scripts 例程来创建文档的深拷贝,但深拷贝功能不能很好地处理图像和表格,所以我永远无法获得完整的复制。如果我可以实现一个 "Save As" 函数,其中操作数是一个现有的唯一 ID,我想这会做我想要的。

有人知道我该怎么做吗?

我对此进行了深入研究,尝试以多种方式设置文件 "large print" 版本的 ID:

  1. 通过copy()var copiedFile = Drive.Files.copy(lpFile, spFile.id, options);
    产生错误:

    Generated IDs are not currently supported for copy requests

  2. 通过insert()var newFile = Drive.Files.insert(lpFile, doc.getBlob(), options);
    产生错误:

    Generated IDs are not supported for Google Docs formats

  3. 通过update()Drive.Files.update(lpFile, lpFile.id, doc.getBlob(), options);
    此方法成功地从小字体文件更新了 "large print" 文件。但是,此特定行使用 Document#getBlob() method, which has issues with formatting and rich content from the Document. In particular, as you mention, images and tables in are not preserved (among other things, like changes to the font, etc.). Compare pre with post

似乎 - 如果可以找到从文档中导出格式化字节内容的适当方法 - update() 方法最有希望。请注意,Apps 脚本客户端库中的 update() 方法需要 Blob 输入(即 doc.getBlob().getBytes() 将不起作用),因此基本限制可能是(缺乏)对丰富格式的支持生成的 Blob 数据中的信息。考虑到这一点,我尝试了几种从 "small print" 文件中获取 "formatted" Blob 数据的方法:

  1. 通过Document#getAs(mimetype)Drive.Files.export(lpFile, lpFile.id, doc.getAs(<type>), options);
    对于看似明智的类型失败并出现错误:

    MimeType.GOOGLE_DOCS: We're sorry, a server error occurred. Please wait a bit and try again.
    MimeType.MICROSOFT_WORD: Converting from application/vnd.google-apps.document to application/vnd.openxmlformats-officedocument.wordprocessingml.document is not supported.

这些错误确实有意义,因为内部 Google Docs MimeType 不可导出(您不能 "download as" 此文件类型,因为数据已保留,但 Google 希望保留it),并且 Document#getAs(mimeType) 的文档表明文档服务仅支持 PDF 导出。事实上,试图用 getAs(mimeType)doc.getBlob() 强制 Blob 失败,错误为:

Converting from application/pdf to application/vnd.openxmlformats-officedocument.wordprocessingml.document is not supported.

  1. 使用 DriveApp 获取 Blob,而不是文档服务:
    Drive.Files.update(lpFile, lpFile.id, DriveApp.getFileById(smallPrintId).getBlob(), options);
    这与 doc.getBlob() 存在相同的问题,并且可能使用相同的内部方法。

  2. 使用DriveApp#getAsDocument#getAs

  3. 有相同的错误

考虑到原生Apps Script实现的局限性,于是我使用高级服务获取了Blob数据。这有点棘手,因为返回的 File 资源实际上不是文件,而是关于文件的元数据。使用 REST API 获取 Blob 需要将文件导出到所需的 MimeType。我们从上面知道 PDF 格式的 Blob 无法正确导入,因为这是上述尝试使用的格式。我们也知道 Google Docs 格式是不可导出的,所以只剩下 MS Word 的 .docx

var blob = getBlobViaURL_(smallPrintId, MimeType.MICROSOFT_WORD);
Drive.Files.update(lpFile, lpFile.id, blob, options);

其中 getBlobViaURL_ 实现了 for the (still-broken) Drive.Files.export() Apps 脚本方法的解决方法。

此方法成功地使用 "small print" 文件 中的确切内容更新现有 "large print" 文件 - 至少对于我的测试文档而言。鉴于它涉及下载内容而不是使用导出方法可用的内部已经存在的数据,因此对于较大的文件它可能会失败。

测试脚本:

function copyContentFromAtoB() {
  var smallPrintId = "some id";
  var largePrintId = "some other id";

  // You must first enable the Drive "Advanced Service" before this will work.
  // Get the file metadata of the to-be-updated file.
  var lpFile = Drive.Files.get(largePrintId);
  // View available options on the relevant Drive REST API pages.
  var options = {
    updateViewedDate: false,
  };
  // Ideally this would use Drive.Files.export, but there is a bug in the Apps Script
  // client library's implementation: https://issuetracker.google.com/issues/36765129
  var blob = getBlobViaURL_(smallPrintId, MimeType.MICROSOFT_WORD);

  // Replace the contents of the large print version with that of the small print version.
  Drive.Files.update(lpFile, lpFile.id, blob, options);
}
// Below function derived from 
function getBlobViaURL_(id, mimeType) {
  var url = "https://www.googleapis.com/drive/v2/files/"+id+"/export?mimeType="+ mimeType;
  var resp = UrlFetchApp.fetch(url, {
    headers: { Authorization: 'Bearer ' + ScriptApp.getOAuthToken()}
  });
  return resp.getBlob();
}