使用 Selection 的 RangeElements 获取 Google 文档中的所有嵌套文本元素

2023-11-30

在类似于上面的文档中,我可以使用以下代码获取所有段落:

var paras = body.getParagraphs();

请注意,上面的代码不仅返回顶级段落,还返回内部的所有子级别段落ListItems, Tables etc.

如何在选定的范围内做同样的事情?以下代码仅返回顶级元素。

const selection = DocumentApp.getActiveDocument().getSelection();
var rangeElements = selection.getRangeElements();

例如,上表包含9个非空段落,如果它们在选择中,我想将它们一一处理。

我想要实现的目标类似于通过尽可能保留格式、表格、列表项等来翻译选择中的文本。


.getRangeElements()返回一个数组范围元素。范围元素是一个包装对象,用于帮助我们处理部分选择。我们可以打电话.getElement()在此数组中的每个项目上获取元素对象这是一个very通用对象,可以代表 Google 文档的几乎任何部分。Elements have a .getType()方法返回一个元素类型枚举;并且有a lot他们!


让我们用目前所知的知识来看看 Google 文档中可能的类型(我已经创建了一个与您相似的(img)举个例子):

function selectionHasWhichTypes() {
  var doc = DocumentApp.getActiveDocument();
  var selection = doc.getSelection();
  var rangeElems = selection.getRangeElements();

  rangeElems.forEach(function(elem){
    var elem = elem.getElement();

    Logger.log(elem.getType());
  });
}

//Logger OUTPUT:
PARAGRAPH
PARAGRAPH
PARAGRAPH
PARAGRAPH
PARAGRAPH
LIST_ITEM
LIST_ITEM
LIST_ITEM
PARAGRAPH
PARAGRAPH
PARAGRAPH
TABLE
PARAGRAPH

Ah Ha!看起来我们只需要处理段落, 项目清单, and TABLE元素类型for now,但让我们保留他们的children也记住(我们会发现这些是 5 个中的 3 个可以生孩子)。这听起来像是一份工作递归函数它将不断深入挖掘子元素,直到我们找到并处理所有子元素。


那么让我们尝试一下吧。下一部分可能看起来令人困惑,但本质上它是查找一个元素,检查它是否有子元素,然后查看它们是否有they有孩子等等。我们also想检查一下我们是否得到了new还要处理的 ElementTypes...

function selectionHasWhichTypes() {
  var doc = DocumentApp.getActiveDocument();
  var selection = doc.getSelection();
  var rangeElems = selection.getRangeElements();

  rangeElems.forEach(function(elem){
    var elem = elem.getElement();

    elemsHaveWhatChildElems(elem, elem.getType());

  });
}

function elemsHaveWhatChildElems(elem, typeChain){
  var elemType = elem.getType();
  if(elemType == "TABLE" || elemType == "LIST_ITEM" || elemType == "PARAGRAPH"){ //Lets see if element is one of our basic 3. If so they could have children.
    var numChildren = elem.getNumChildren(); //How many children are there?
    if(numChildren > 0){
      for(var i = 0; i < numChildren; i++){ //Let's go through them.
        var child = elem.getChild(i);
        elemsHaveWhatChildElems(child, typeChain + "." + child.getType()); //Recursion step to look for more children.
      }
    }else{
       Logger.log(typeChain); //Let's log the chain of Parent to Child elements.
    }
  }else{
    Logger.log("*" + typeChain); //Let's mark the new elemTypeChains we have not seen.
  }
}

//Logger OUTPUT:
*PARAGRAPH.TEXT
PARAGRAPH
*PARAGRAPH.HORIZONTAL_RULE
PARAGRAPH
*PARAGRAPH.TEXT
*LIST_ITEM.TEXT
*LIST_ITEM.TEXT
*LIST_ITEM.TEXT
PARAGRAPH
*PARAGRAPH.TEXT
PARAGRAPH
*TABLE.TABLE_ROW
*TABLE.TABLE_ROW
PARAGRAPH

好吧,日志的每一行都是一系列元素及其子元素。我们有一些新元素类型 (水平规则, 表行, and TEXT)。如果一条链只是一个Paragraph并且没有孩子,如“段落”所示。我们可以忽略它因为它是一个空行。我们也可以忽略HORIZONTAL_RULE作为这个明显地不会包含文本。

如果我们已经到达一个 TEXT 元素这意味着我们可以执行我们的功能(即对于 OP 来说,这将是一个翻译),就像我们对 LIST_ITEM 和 PARAGRAPH 所做的那样。然而,我们still必须处理TableRow对象(记录如下:TABLE.TABLE_ROW)。这是类似于我们的主要 3 个要素并可以与我们的if(elemType == "TABLE" || elemType == "LIST_ITEM" || elemType == "PARAGRAPH")这会改变为if(elemType == "TABLE" || elemType == "LIST_ITEM" || elemType == "PARAGRAPH" || elemType == "TABLE_ROW").

这为我们的链中提供了另一个新元素;表格单元格(日志如下:TABLE.TABLE_ROW.TABLE_CELL),我们可以again添加到我们的 if 语句中,使其:if(elemType == "TABLE" || elemType == "LIST_ITEM" || elemType == "PARAGRAPH" || elemType == "TABLE_ROW" || elemType == "TABLE_CELL")


是时候看看会发生什么了当我们处理完表元素类型时。

function selectionHasWhichtypeChains() {
  var doc = DocumentApp.getActiveDocument();
  var selection = doc.getSelection();
  var rangeElems = selection.getRangeElements();

  rangeElems.forEach(function(elem){
    var elem = elem.getElement();

    elemsHaveWhatChildElems(elem, elem.getType());

  });
}

function elemsHaveWhatChildElems(elem, typeChain){
  var elemType = elem.getType();
  if(elemType == "TABLE" || elemType == "LIST_ITEM" || elemType == "PARAGRAPH" || elemType == "TABLE_ROW" || elemType == "TABLE_CELL"){ //Lets see if element is one of our basic 5 if so they could have children.
    var numChildren = elem.getNumChildren(); //How many children are there?
    if(numChildren > 0){
      for(var i = 0; i < numChildren; i++){ //Let's go through them.
        var child = elem.getChild(i);
        elemsHaveWhatChildElems(child, typeChain + "." + child.getType()); //Recursion step to look for more children.
      }
    }else{
       Logger.log(typeChain); //Let's log the chain of Parent to Child elements.
    }
  }else{
    Logger.log("*" + typeChain); //Let's mark the new elemTypeChains we have not seen.
  }
}

//Logger OUTPUT:
*PARAGRAPH.TEXT
PARAGRAPH
*PARAGRAPH.HORIZONTAL_RULE
PARAGRAPH
*PARAGRAPH.TEXT
*LIST_ITEM.TEXT
*LIST_ITEM.TEXT
*LIST_ITEM.TEXT
PARAGRAPH
*PARAGRAPH.TEXT
PARAGRAPH
*TABLE.TABLE_ROW.TABLE_CELL.PARAGRAPH.TEXT
*TABLE.TABLE_ROW.TABLE_CELL.TABLE.TABLE_ROW.TABLE_CELL.PARAGRAPH.TEXT
*TABLE.TABLE_ROW.TABLE_CELL.TABLE.TABLE_ROW.TABLE_CELL.PARAGRAPH.TEXT
*TABLE.TABLE_ROW.TABLE_CELL.TABLE.TABLE_ROW.TABLE_CELL.PARAGRAPH.TEXT
*TABLE.TABLE_ROW.TABLE_CELL.TABLE.TABLE_ROW.TABLE_CELL.PARAGRAPH.TEXT
TABLE.TABLE_ROW.TABLE_CELL.PARAGRAPH
*TABLE.TABLE_ROW.TABLE_CELL.PARAGRAPH.TEXT
*TABLE.TABLE_ROW.TABLE_CELL.PARAGRAPH.HORIZONTAL_RULE
*TABLE.TABLE_ROW.TABLE_CELL.PARAGRAPH.TEXT
*TABLE.TABLE_ROW.TABLE_CELL.PARAGRAPH.TEXT
PARAGRAPH

这很棒!我们已经深入到每个父元素并达到了a 文本元素 or a 空白段落!从这里我们可以稍微修改我们的代码以添加我们想要执行的功能,同时保持文档的结构:

function myFunction() {
  var doc = DocumentApp.getActiveDocument();
  var selection = doc.getSelection();
  var rangeElems = selection.getRangeElements(); //Get main Elements of selection

  rangeElems.forEach(function(elem){ //Let's rn through each to find ALL of their children.
    var elem = elem.getElement(); //We have an ElementType. Let's get the full element.
    getNestedTextElements(elem, elem.getType()); //Time to go down the rabbit hole.
  });
}

function getNestedTextElements(elem, typeChain){
  var elemType = elem.getType();
  if(elemType == "TABLE" || elemType == "LIST_ITEM" || elemType == "PARAGRAPH" || elemType == "TABLE_ROW" || elemType == "TABLE_CELL"){ //Lets see if element is one of our basic 5, if so they could have children.
    var numChildren = elem.getNumChildren(); //How many children are there?
    if(numChildren > 0){
      for(var i = 0; i < numChildren; i++){ //Let's go through them.
        var child = elem.getChild(i);
        getNestedTextElements(child, typeChain + "." + child.getType()); //Recursion step to look for more children.
      }
    }
  }else if(elemType == "TEXT"){
    //THIS IS WHERE WE CAN PERFORM OUR OPERATIONS ON THE TEXT ELEMENT
    var text = elem.getText();


  }else{
    Logger.log("*" + typeChain); //Let's log the new elem we dont deal with now - for future proofing.
  }
}

繁荣!完毕。我知道这是一篇非常长的文章,但我已将解决方案的每个部分分解为多个部分,以帮助新的 Apps 脚本编码人员了解选择的结构(我猜还有文档正文)以及如何在结构发生变化时修改它非常复杂(许多嵌套元素)。我真的希望这有帮助。如果有人看到可以改进的部分,请告诉我。


作为OP的注释:请注意,这不一定处理元素的部分选择,但是可以通过稍微修改第一个函数来检查来轻松处理isPartial() on the 范围元素.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Selection 的 RangeElements 获取 Google 文档中的所有嵌套文本元素 的相关文章

  • Google Apps 脚本:如何水平对齐 inlineImage

    我有以下代码 它是一个更大程序的一部分 我正在尝试将图像从我的 Google 驱动器插入到 Google 文档中 并调整其大小并居中 到目前为止 我能够让程序插入图像并调整其大小 但我不知道如何使 inlineImage 居中 我是使用谷歌
  • 正则表达式 - 使用正则表达式提取电子邮件文档的子字符串

    我正在尝试使用正则表达式提取电子邮件文档的子字符串 我正在在线测试正则表达式 它运行得很好 在线正则表达式测试器 https regex101 com r BbWBPk 1 我有一个功能可以检查 Google Apps 脚本上的正则表达式
  • 根据条件格式化货币

    Google Apps 脚本新手 但有一些 VBA 编码经验 我希望能够根据不同的单元格输入决定单元格的数字格式 eg Col A 客户名称 验证范围 B 栏 货币类型 英镑 美元 欧元 经过验证的列表 Col C 费用 100 用户免费类
  • 如何下载以前保存的 Google Apps 脚本修订版本?

    我仍在尝试从中恢复不知何故 丢失 了 Google Apps 脚本 https stackoverflow com questions 33697789 当我创建脚本的副本以将代码分叉到另一个项目时 我的想法是尝试通过驱动器 API 下载
  • 如何使用脚本格式化 Google 文档中的文本

    我想编写一个脚本来查找所有特定单词并格式化它们的颜色 我尝试了以下操作 但似乎不起作用 function ChangeColor var body DocumentApp getActiveDocument getBody var mywo
  • Google Web Apps - 获取用户电子邮件但以所有者身份运行脚本

    我最近迷上了谷歌网络应用程序 但我遇到了一些进退两难的问题 我正在尝试构建一个对非常特定的用户开放的应用程序 并且他们正在查看的数据根据 其访问组进行过滤 在谷歌表格中 我列出了用户电子邮件及其各自的访问组 A 列 电子邮件 B 列 访问组
  • 清除内容并从另一张纸复制

    我编写了一个脚本 旨在清除 Google Sheets 电子表格的内容并复制并粘贴另一个工作表的内容 需要清除的工作表称为 NEW SHEET 要复制的工作表称为 Database 由于某种原因 该脚本目前无法运行 当我运行它时什么也没有发
  • 在应用程序脚本中将 .XLS 转换为 Google 表格的最有效方法是什么?

    我每周都会自动将 XLS 文件下载到 Google 云端硬盘 我想每周自动将最新下载的 XLS 文件转换为 Google 表格格式 因此转到特定的 Google 驱动器文件夹 查找最新或未转换的 XLS 文件 转换为 Google 表格格式
  • javascript 对象是否像 Ruby 一样“开放”?

    在 Ruby 中 我可以使用与声明自己的语法相同的语法来添加和修改任何类 对象或方法的功能 因为 Ruby 有 开放类 JavaScript 是这样的吗 举个例子 就我而言 我想更改 Google Apps 脚本处理 URL 对象的方式 以
  • Google 文档如何处理编辑冲突?

    我一直在尝试编写自己的 Javascript 编辑器 其功能类似于 Google Docs 允许多人同时使用 我不明白一件事 假设用户 A 和用户 B 直接相互连接 网络延迟为 10 毫秒 我假设编辑器使用 diff 系统 据我了解 Doc
  • Google App脚本:无法保留前导零,因为它被自动删除

    我是谷歌脚本的新手 我有一个像下面这样的场景 我有 Sheet1 其中包含 A 列和 B 列 通常我尝试将十进制值存储到其中 我的意思是A列中的整数部分和B列中的小数部分 例如 场景一 如果值为 23 75 则 Column A 应为 23
  • 上传到google脚本中的特定文件夹

    所以我想制作一个表单 将文件 照片 视频上传到 Google Drive 中的特定文件夹 文件 照片 视频 但我不知道如何在 Google Apps 脚本中制作 我尝试了这样的操作 并在控制台中出现错误 无效的参数侦听器 所以这里有一个索引
  • Google 表单根据提交的值将文件上传到特定的新文件夹

    我的表单有 2 个字段 假设表单的名称是CV Drops Name 上传文件按钮 因此 默认情况下 当人们上传文件时 它将保存在我的 Google Drive 文件夹下CV Drops 我想要的是根据字段中的输入将文件放置在子文件夹中NAM
  • ChartRangeFilter 作为谷歌时间轴图表的缩放功能,可使用数据视图从专用谷歌电子表格中读取数据

    我的目标是整合Whitehat 提供的这种缩放功能 https stackoverflow com questions 49306638 google timeline visualization dont change series ro
  • 找不到 OAuth2 参数

    我正在尝试使用 OAuth 2 0 来授权 google docs API 根据谷歌给出的例子https developers google com google apps documents list authorizing reques
  • google apps 脚本 ==> UrlFetchApp、方法 GET 和 cookie

    我使用 UrlFetchApp 发送用户和密码 POST 方法 获取cookie后 并在其他请求中使用 GET方法 但是这个新请求不起作用 我认为这个 cookie 在这个新请求中没有正确使用 谁能帮我 var opt method pos
  • Google Apps 脚本返回错误“超出限制:URLFetch URL 长度”

    YouTube 数据 api v3 nextPageToken 太长 导致 Google Apps 脚本返回错误Limit Exceeded URLFetch URL Length当我尝试时UrlFetchApp fetch request
  • 如何删除“其他用户”可安装触发器?

    有没有办法删除 其他用户 可安装的触发器 足够幸运地猜测要删除哪个用户只会显示他们的触发器已禁用 但仍然需要您登录他们的 Gmail 才能删除它 当您是电子表格的 所有者 时 这有点令人担忧 您无法删除其他用户的触发器 脚本的触发器与用户的
  • Session.getActiveUser.getEmail() 空白?谷歌表格

    我想检查点击该特定按钮的用户 当我以我的帐户登录时单击它时 它运行正常 但如果其他人运行它 它就是空白的 如何获取登录用户的电子邮件 ID 这是我的代码 function check User var ui SpreadsheetApp g
  • 根据 Google Apps 脚本中的另一个数组过滤数组

    我对 JavaScript 相当陌生 可能需要一些帮助来解决我在处理 Google Apps 脚本时遇到的问题 我打算做的是根据数组过滤数据 该数组是从特定工作表中的特定单元格中获取的 其中包含我不想保留在数据中的字符串元素 换句话说 包含

随机推荐

  • 按日期对多列重新排序和重新分组

    我对此有点困惑 希望得到一些帮助 这是我的数据 Col A Col B Col C Col D Col E Col F FRANCE ITALY DATE Installs Uninstalls DATE Installs Uninstal
  • 在 C++ 中设置单独的位[重复]

    这个问题在这里已经有答案了 我有一个 5 字节数据元素 我需要一些帮助来弄清楚如何在 C 中设置这些字节之一的单个位 请参阅下面我的示例代码 char m TxBuf 4 我想将位 2 设置为字节的高位m TxBuf 1 00000 0 0
  • Android 中通过触摸事件进行反向地理编码

    我通过此堆栈溢出浏览了几篇文章以及其他与反向地理编码相关的文章 我打算从触摸事件中查找具有给定纬度和经度的地点的名称 我从触摸事件中获取了纬度和经度 但无法从该地理坐标中获取地址 它传递异常而不是在尝试区域中 这是代码 public boo
  • 在 Objective C 中检测 PNG 文件是否损坏

    我正在使用 NSURLRequest 下载 jpg 和 png 这工作正常 但有时文件会损坏 我见过捕获错误 损坏的 JPEG 数据 数据段过早结束并使其适用于 jpg 有谁知道对 png 做同样的事情的方法吗 即以编程方式检查 png 数
  • 使用 event.which 来验证用户是否按下空格键在 Firefox 中不起作用

    我想要一个脚本来验证按下的键是否是 空格键 键码 32 我注意到 IE 使用其他函数名称 我尝试了很多在这里找到的解决方案 event event window event IE does not pass event to the fun
  • 如何使用C#读取从asp.net页面传递的参数?

    我是 ASP net 新手 如何读取从 ASP net 页面传递的参数 任何小例子都会受到赞赏 这对我来说只是一个开始 使用您的示例 URL string id Request QueryString id string nam Reque
  • Spring Cloud Gateway转发客户端证书

    我正在尝试将 spring cloud gateway 用于基于 spring boot 的服务 该服务使用 ssl 和客户端身份验证 问题是 通过 api 网关从客户端调用服务总是失败 并显示 certificate unknown 没有
  • Phonegap 视频捕捉崩溃

    我制作了一个相对简单的phonegap应用程序 能够捕获图像和视频并将其上传到服务器 图像工作正常 但是当我调用捕获视频时 会出现相机 UI 当我接受视频时 应用程序崩溃并在 logcat 中出现以下错误 java lang Runtime
  • :touch CSS 伪类或类似的东西?

    我正在尝试制作一个按钮 这样当用户单击它时 它会在按住鼠标按钮的同时更改其样式 如果在移动浏览器中触摸它 我还希望它以类似的方式改变其样式 对我来说 看似显而易见的事情是使用 CSS active 伪类 但这不起作用 我尝试过 focus
  • R SHINY - 条件面板输出偏移?

    这篇文章是相关的R闪亮 复选框和条件面板问题 我在这里成功地创建了该问题的 MRE 再次总结一下 当单击第二个复选框或同时单击第一个和第二个复选框时 数据帧输出会发生移动 我希望它显示在与单击时相同的位置第一个复选框 library shi
  • 使用 Qt 中的命名参数列表发出 HTTP POST 请求

    我需要从 Qt 应用程序向服务器发出 HTTP POST 请求 POST 请求将包含命名值列表 即键 值对 它们主要是字母数字字符串 但可以包含特殊字符 例如引号 空格等 在 Qt 中执行此类 POST 请求的规范方法是什么 当前答案适用于
  • 将 Swift 数组转换为 NSData 以进行 NSUserDefaults.StandardUserDefaults 持久存储

    我正在尝试通过制作一个小应用程序来了解 Swift 在相对熟悉 Obj C 之后 我想使用 NSUserDefaults 持久保存少量数据 但我遇到了问题 我初始化一个空的元组数组 如下所示 var costCategoryArray na
  • 无法将 Ruby on Rails 连接到远程 mysql 数据库

    我正在尝试将我的rails 3应用程序连接到godaddy服务器上托管的mysql数据库 我可以使用 mysql 客户端进行远程连接 但在运行应用程序时却无法进行连接 我能够连接本地 mysql 但是当我尝试连接到远程托管数据库时 出现此错
  • 由于编码问题,WebClient.DownloadString 导致字符损坏,但浏览器正常

    下面的代码 var text new WebClient DownloadString http export arxiv org api query search query au Freidel L start 0 max result
  • Pandas - 当字符串与格式匹配时出现“时间数据与格式不匹配”​​错误?

    我收到一个值错误 指出我的数据与格式不匹配 不确定这是一个错误还是我在这里遗漏了一些东西 我指的是本文档对于字符串格式 奇怪的部分是 如果我将 数据 Dataframe 写入 csv 并读取它 然后调用下面的函数将转换日期 所以我不确定为什
  • php 邮件功能不发送电子邮件/发送电子邮件花费太长时间

    我有一个机架空间云 我想在其中设置 LAMP 服务器有CentOS 我安装了sendmail并且php邮件功能使用这个 但是使用php邮件功能发送电子邮件需要很长时间
  • Spark SQL - 转义查询字符串

    我不敢相信我会问这个但是 如何使用 SCALA 在 SPARK SQL 中转义 SQL 查询字符串 我已经厌倦了一切 到处寻找 我认为 apache commons 库可以做到这一点 但没有运气 import org apache comm
  • 如何更改 Handsontable 中已更改单元格的颜色?

    我正在使用 Handsontable 插件 当用户更改单元格中的值时 它应该变成黄色 以便他们可以跟踪更改的内容 在本例中 黄色是类 changeInput 棘手的部分是 当您双击单元格进行更改时 它会变成文本区域 而不再是 td 有任何想
  • 在 matplotlib 中显示表面前面的轮廓

    我一直在寻找答案 但我似乎不明白为什么在我的代码中我无法让投影轮廓显示在表面 后面 from mpl toolkits mplot3d import axes3d import matplotlib pyplot as plt from m
  • 使用 Selection 的 RangeElements 获取 Google 文档中的所有嵌套文本元素

    在类似于上面的文档中 我可以使用以下代码获取所有段落 var paras body getParagraphs 请注意 上面的代码不仅返回顶级段落 还返回内部的所有子级别段落ListItems Tables etc 如何在选定的范围内做同样