GS_*_*Dan 1 named-ranges google-docs-api node.js google-apps-script
将 Google Docs/Drive API 与 Node 结合使用,我成功创建了一个服务,该服务生成“模板”样式文档,其中包含 namedRanges 供其他用户写入。我想使用 Google Docs API 来读取在这些范围内输入的文本,但看不到一种干净的方法。鉴于我有每个范围的开始和结束索引,我认为这将非常简单!不幸的是,我看不到任何内置的方法?
目前看起来我将不得不请求整个谷歌文档,并且对于我正在观看的每个范围,比较每个节点的开始/结束索引并递归遍历树直到它们匹配。没有更好的方法来做到这一点吗?
干杯
编辑:
下面 Tanaike 的解决方案更简洁,但我已经有一个版本可以在我的 Firebase 函数上运行,所以我想我不妨分享一下。此代码检索具有给定 ID 的 Google 文档,并将 namedRanges 的内容作为字符串存储在 Firebase 实时数据库中,通过“BBCode”样式标签保持图像和表格完整无缺。下面的相关代码(请注意,我知道每个 namedRange 都在表格单元格内,这使得查找它们更容易):
async function StoreResponses(oauth2Client, numSections, documentId, meetingId, revisionId, roomId)
{
var gdocsApi = google.docs({version: 'v1', auth: oauth2Client});
return gdocsApi.documents.get({ "documentId": documentId })
.then((document) => {
var ranges = document.data.namedRanges;
var docContent = document.data.body.content;
var toStore = [];
for(var i = 0; i < numSections; i++)
{
var range = ranges[`zoomsense_section_${i}`].namedRanges[0].ranges[0]
// loop through document contents until we hit the right index
for(var j = 0; j < docContent.length; j++)
{
if(docContent[j].startIndex <= range.startIndex && docContent[j].endIndex >= range.endIndex)
{
// we know that the ranges are inside single table cells
var sectionContents = docContent[j].table.tableRows[0].tableCells[0].content;
toStore.push(readStructuralElementsRecursively(document, sectionContents));
}
}
}
return db.ref(`/data/gdocs/${meetingId}/${roomId}/${documentId}/revisions/${revisionId}/responses`).set(toStore);
})
.catch((exception) => {
console.error(exception)
res.status(500).send(exception);
})
}
Run Code Online (Sandbox Code Playgroud)
// uses https://developers.google.com/docs/api/samples/extract-text
function readStructuralElementsRecursively(document, elements)
{
var text = "";
elements.forEach(element => {
if(element.paragraph)
{
element.paragraph.elements.forEach(elem => {
text += readParagraphElement(document, elem);
});
}
else if(element.table)
{
// The text in table cells are in nested Structural Elements, so this is recursive
text += "[table]"
element.table.tableRows.forEach(row => {
text += "[row]"
row.tableCells.forEach(cell => {
text += `[cell]${readStructuralElementsRecursively(document, cell.content)}[/cell]`;
})
text += "[/row]"
})
text+= "[/table]"
}
});
return text;
}
Run Code Online (Sandbox Code Playgroud)
// handle text and inline content
function readParagraphElement(document, element)
{
if(element.textRun)
{
// standard text
return element.textRun.content;
}
if(element.inlineObjectElement)
{
var objId = element.inlineObjectElement.inlineObjectId;
var imgTag = "\n[img]404[/img]"
try
{
var embeddedObj = document.data.inlineObjects[objId].inlineObjectProperties.embeddedObject;
if(embeddedObj.imageProperties)
{
// this is an image
imgTag = `[img]${embeddedObj.imageProperties.contentUri}[/img]`
}
else if(embeddedObj.embeddedDrawingProperties)
{
// this is a shape/drawing
// can't find any way to meaningfully reference them externally,
// so storing the ID in case we can do it later
imgTag = `[drawing]${objId}[/drawing]`
}
}
catch(exception)
{
console.log(exception)
}
return imgTag;
}
}
Run Code Online (Sandbox Code Playgroud)
我相信你的目标如下。
为了实现上述目标,我想提出以下解决方法。
不幸的是,在当前阶段,没有方法可以直接从 Google Docs API 中的命名范围中检索值。我相信将来可能会添加这种方法,因为 Docs API 现在正在增长。因此,作为当前使用 Docs API 的解决方法,需要执行以下流程。
startIndex
并endIndex
使用命名范围的名称。startIndex
和检索值endIndex
。这已经在你的问题中提到了。使用Google Docs API时,现阶段需要使用该方法。但是当使用 Google Document 服务时,可以通过命名范围的名称和/或 ID 直接检索命名范围的值。在这个答案中,我想提出这种方法作为另一种解决方法。
请执行以下流程。
Web Apps 的示例脚本是 Google Apps 脚本。所以请创建一个 Google Apps Script 项目。为了使用文档服务,在这种情况下,使用 Web Apps 作为包装器。
如果你想直接创建它,请访问https://script.new/。在这种情况下,如果您未登录 Google,则会打开登录屏幕。所以请登录谷歌。这样,Google Apps Script 的脚本编辑器就打开了。
请将以下脚本(Google Apps 脚本)复制并粘贴到脚本编辑器中。此脚本适用于 Web 应用程序。
function doGet(e) {
Object.prototype.getText = function() {return this.getRange().getRangeElements().map(e => e.getElement().asText().getText().slice(e.getStartOffset(), e.getEndOffsetInclusive() + 1))};
const doc = DocumentApp.openById(e.parameter.id);
let res;
if (e.parameter.name) {
const ranges = doc.getNamedRanges(e.parameter.name);
res = ranges.length > 0 ? ranges[0].getText() : [];
} else if (e.parameter.rangeId) {
const range = doc.getNamedRangeById(e.parameter.rangeId.split(".")[1]);
res = range ? range.getText() : [];
} else {
res = [];
}
return ContentService.createTextOutput(JSON.stringify(res));
}
Run Code Online (Sandbox Code Playgroud)
https://www.googleapis.com/auth/drive.readonly
和https://www.googleapis.com/auth/drive
。这些范围是访问 Web 应用程序所必需的。https://script.google.com/macros/s/###/exec
.
您可以使用以下脚本从 Google 电子表格中检索值。
const request = require("request");
const url = "https://script.google.com/macros/s/###/exec"; // Please set the URL of Web Apps.
let qs = {
id: "###", // Please set the Document ID.
name: "###", // Please set the name of named range.
// rangeId: "kix.###", // Please set the ID of named range.
};
let options = {
url: url,
qs: qs,
method: "get",
};
request(options, (err, res, result) => {
if (err) {
console.log(err);
return;
}
console.log(result);
});
Run Code Online (Sandbox Code Playgroud)
let qs = {id: "###", name: "###"};
. 当您想使用命名范围的 ID 时,请使用let qs = {id: "###", rangeId: "kix.###"};
. 归档时间: |
|
查看次数: |
458 次 |
最近记录: |