2

我的目标是解析 Google 文档中的 TableOfContents 元素并将其写入另一个。我想对文件夹中的每个文档执行此操作。费心将每个文档转换为 DocsList 生成的类型,这样我就可以使用这种方法 [ DocumentApp 生成的文档没有这种方法。为什么,我不明白,否则这两个“文档”在查找零件时是相似的。],我发现我得到的是一个 SearchResult。这种难以捉摸的结构是如何使用的?我尝试将其转换为 TableOfContents 元素 [ele = searchResult.asTableOfContents()],它不会出错,但我所做的一切都无法让我解析其子元素以恢复其文本作品。有趣的是,如果您通过解析文档获得 TableOfContents 元素'

有人会谈谈这个问题。我肯定会喜欢一个代码片段,因为我无处可去,而且我已经为此投入了几个小时。

4

2 回答 2

4

asTableOfContents()方法仅用于帮助编辑器的自动完成功能。它没有运行时影响,并且不能用于转换为不同的类型。(请参阅ContainerElement 文档。)

要解析目录,首先从SearchResult中检索元素。下面是一个通过文档目录中的项目生成项目信息数组的示例。

示例文档

截屏

解析结果

在一个带有几个标题和目录的简单文档上,它产生了以下内容:

[13-08-20 16:31:56:415 EDT] 
[
  {text=Heading 1.0, linkUrl=#heading=h.50tkhklducwk, indentFirstLine=18.0, indentStart=18.0},
  {text=Heading 1.1, linkUrl=#heading=h.ugj69zpoikat, indentFirstLine=36.0, indentStart=36.0},
  {text=Heading 1.2, linkUrl=#heading=h.xb0y0mu59rag, indentFirstLine=36.0, indentStart=36.0},
  {text=Heading 2.0, linkUrl=#heading=h.gebx44eft4kq, indentFirstLine=18.0, indentStart=18.0}
]

代码

function test_parseTOC() {
  var fileId = '--Doc-ID--';
  Logger.log( parseTOC( fileId ) );
}

function parseTOC( docId ) {
  var contents = [];
  var doc = DocumentApp.openById(docId);

  // Define the search parameters.
  var searchElement  = doc.getBody();
  var searchType = DocumentApp.ElementType.TABLE_OF_CONTENTS;

  // Search for TOC. Assume there's only one.
  var searchResult = searchElement.findElement(searchType);

  if (searchResult) {
    // TOC was found
    var toc = searchResult.getElement().asTableOfContents();

    // Parse all entries in TOC. The TOC contains child Paragraph elements,
    // and each of those has a child Text element. The attributes of both
    // the Paragraph and Text combine to make the TOC item functional.
    var numChildren = toc.getNumChildren();
    for (var i=0; i < numChildren; i++) {
      var itemInfo = {}
      var tocItem = toc.getChild(i).asParagraph();
      var tocItemAttrs = tocItem.getAttributes();
      var tocItemText = tocItem.getChild(0).asText();

      // Set itemInfo attributes for this TOC item, first from Paragraph
      itemInfo.text = tocItem.getText();                // Displayed text
      itemInfo.indentStart = tocItem.getIndentStart();  // TOC Indentation
      itemInfo.indentFirstLine = tocItem.getIndentFirstLine();
      // ... then from child Text
      itemInfo.linkUrl = tocItemText.getLinkUrl();      // URL Link in document
      contents.push(itemInfo);
    }
  }

  // Return array of objects containing TOC info
  return contents;
}

坏消息

坏消息是,您可以对脚本中的目录执行的操作有限。您不能插入 TOC 或将新项目添加到现有项目。

请参阅问题跟踪器中的问题2502,并为其添加星标以获取更新。

如果您可以使用 DocsList 与 DocumentApp 发布代码或解释您的问题,则可以查看。Google Document 的元素只能通过 DocumentApp 进行操作。

于 2013-08-20T20:39:42.750 回答
0

我修改了上面的代码以仅在具有所需级别(即 h1、h2)的表中重新创建 TOC。唯一需要注意的是 TOC 必须在运行之前存在并更新。

function findToc(body, level = 2) {
  const indent = 18;
  let contents = [];

  const tocType = TABLE_OF_CONTENTS;
  const tocContainer = body.findElement(tocType);

  if (tocContainer) {
    // TOC was found
    const toc = tocContainer.getElement().asTableOfContents();
    const totalLines = toc.getNumChildren();

    for (let lineIndex = 0; lineIndex < totalLines; lineIndex++) {
      const tocItem = toc.getChild(lineIndex).asParagraph();
      const { INDENT_START } = tocItem.getAttributes();

      const isDesiredLevel = Number(INDENT_START) <= indent * (level - 1);

      if (isDesiredLevel) {
        contents.push(tocItem.copy());
      }
    }

  }

  return contents;
}

function addToTable(cellText) {
  body = DocumentApp.openById(docId).getBody();

  const table = body.appendTable();
  const tr = table.insertTableRow(0);
  const td = tr.insertTableCell(0);

  cellText.forEach(text => {
    td.appendParagraph(text);
  })
}

function parseTOC(docId) {
  body = DocumentApp.openById(docId).getBody();
  const contents = findToc(body);
  addToTable(contents);
}
于 2019-12-15T02:05:51.753 回答