借助 Google 文档 API,您可以访问文档中的任何标签页中的内容。
什么是标签页?
Google 文档具有一个名为标签页的组织层。Google 文档允许用户在单个文档中创建一个或多个标签页,这与 Google 表格中目前的标签页类似。每个标签页都有自己的标题和 ID(附加在网址中)。标签页还可以包含子标签页,即嵌套在其他标签页下的标签页。
对文档资源中文档内容表示方式的结构性更改
以前,文档没有标签页的概念,因此 Document
资源通过以下字段直接包含所有文本内容:
document.body
document.headers
document.footers
document.footnotes
document.documentStyle
document.suggestedDocumentStyleChanges
document.namedStyles
document.suggestedNamedStylesChanges
document.lists
document.namedRanges
document.inlineObjects
document.positionedObjects
由于新增了标签页的结构层次,这些字段在语义上不再代表文档中所有标签页的文本内容。基于文本的内容现在显示在不同的层中。您可以使用 document.tabs
访问 Google 文档中的标签页属性和内容,它是一个 Tab
对象列表,每个对象都包含上述所有文本内容字段。后续部分提供了简要概览;标签页 JSON 表示法也提供了更多详细信息。
访问“标签页”属性
使用 tab.tabProperties
访问标签页属性,其中包括标签页的 ID、标题和位置等信息。
访问标签页中的文本内容
标签页中的实际文档内容会显示为 tab.documentTab
。您可以使用 tab.documentTab
访问上述所有文本内容字段。例如,您应使用 document.tabs[indexOfTab].documentTab.body
,而不是 document.body
。
标签页层次结构
在 API 中,子标签页表示为 Tab
上的 tab.childTabs
字段。如需访问文档中的所有标签页,需要遍历子标签页的“树”。例如,假设有一个文档包含如下标签页层次结构:
如需从“3.1.2”标签页检索 Body
,您需要访问 document.tabs[2].childTabs[0].childTabs[1].documentTab.body
。请参阅后面部分中的示例代码块,其中提供了用于迭代文档中所有标签页的示例代码。
方法变更
随着标签页的引入,每个文档方法都发生了一些变化,您可能需要更新代码。
documents.get
默认情况下,系统不会返回所有标签页内容。开发者应更新其代码,以访问所有标签页。documents.get
方法会公开一个 includeTabsContent
参数,用于配置是否在响应中提供所有标签页中的内容。
- 如果
includeTabsContent
设置为true
,documents.get
方法将返回一个已填充document.tabs
字段的Document
资源。直接位于document
上的所有文本字段(例如document.body
)将保持空白状态。 - 如果未提供
includeTabsContent
,则Document
资源(例如document.body
)中的文本字段将仅填充第一个标签页中的内容。document.tabs
字段将为空,并且系统不会返回其他标签页中的内容。
documents.create
documents.create
方法会返回一个 Document
资源,表示创建的空文档。返回的 Document
资源将在文档的文本内容字段和 document.tabs
中填充空白文档内容。
document.batchUpdate
每个 Request
都包含一种用于指定要应用更新的标签页的方法。默认情况下,如果未指定标签页,则在大多数情况下,Request
将应用于文档中的第一个标签页。ReplaceAllTextRequest
、DeleteNamedRangeRequest
和 ReplaceNamedRangeContentRequest
是三个特殊请求,默认会应用于所有标签页。
如需了解详情,请参阅 Request
的文档。
内部链接的更改
用户可以创建指向文档中标签页、书签和标题的内部链接。随着标签页功能的引入,Link
资源中的 link.bookmarkId
和 link.headingId
字段无法再表示文档中特定标签页中的书签或标题。
开发者应更新其代码,以便在读写操作中使用 link.bookmark
和 link.heading
。它们使用 BookmarkLink
和 HeadingLink
对象公开内部链接,每个对象都包含相应书签或标题的 ID 以及其所在标签页的 ID。此外,link.tabId
还会公开指向标签页的内部链接。
documents.get
响应的链接内容也可能因 includeTabsContent
参数而异:
- 如果
includeTabsContent
设置为true
,则所有内部链接都将显示为link.bookmark
和link.heading
。旧版字段将不再使用。 - 如果未提供
includeTabsContent
,则在包含单个标签页的文档中,指向该单个标签页中的书签或标题的任何内部链接仍会显示为link.bookmarkId
和link.headingId
。在包含多个标签页的文档中,内部链接将显示为link.bookmark
和link.heading
。
在 document.batchUpdate
中,如果使用某个旧版字段创建内部链接,系统会将相应书签或标题视为来自 Request
中指定的标签页 ID。如果未指定标签页,则系统会认为它来自文档中的第一个标签页。
链接 JSON 表示法提供了更详细的信息。
标签页的常见使用模式
以下代码示例介绍了与标签页互动的各种方式。
读取文档中所有标签页的内容
在标签页功能推出之前执行此操作的现有代码可以迁移为支持标签页,方法是将 includeTabsContent
参数设置为 true
、遍历标签页树层次结构,并通过 Tab
和 DocumentTab
(而非 Document
)调用 getter 方法。以下部分代码示例基于从文档中提取文本中的代码段。该视频展示了如何打印文档中每个标签页中的所有文本内容。此标签页遍历代码可适用于许多其他不关心标签页实际结构的用例。
Java
/** Prints all text contents from all tabs in the document. */ static void printAllText(Docs service, String documentId) throws IOException { // Fetch the document with all of the tabs populated, including any nested // child tabs. Document doc = service.documents().get(documentId).setIncludeTabsContent(true).execute(); List<Tab> allTabs = getAllTabs(doc); // Print the content from each tab in the document. for (Tab tab: allTabs) { // Get the DocumentTab from the generic Tab. DocumentTab documentTab = tab.getDocumentTab(); System.out.println( readStructuralElements(documentTab.getBody().getContent())); } } /** * Returns a flat list of all tabs in the document in the order they would * appear in the UI (top-down ordering). Includes all child tabs. */ private List<Tab> getAllTabs(Document doc) { List<Tab> allTabs = new ArrayList<>(); // Iterate over all tabs and recursively add any child tabs to generate a // flat list of Tabs. for (Tab tab: doc.getTabs()) { addCurrentAndChildTabs(tab, allTabs); } return allTabs; } /** * Adds the provided tab to the list of all tabs, and recurses through and * adds all child tabs. */ private void addCurrentAndChildTabs(Tab tab, List<Tab> allTabs) { allTabs.add(tab); for (Tab tab: tab.getChildTabs()) { addCurrentAndChildTabs(tab, allTabs); } } /** * Recurses through a list of Structural Elements to read a document's text * where text may be in nested elements. * * <p>For a code sample, see * <a href="https://developers.google.com/docs/api/samples/extract-text">Extract * the text from a document</a>. */ private static String readStructuralElements(List<StructuralElement> elements) { ... }
读取文档中第一个标签页的内容
这类似于读取所有标签页。
Java
/** Prints all text contents from the first tab in the document. */ static void printAllText(Docs service, String documentId) throws IOException { // Fetch the document with all of the tabs populated, including any nested // child tabs. Document doc = service.documents().get(documentId).setIncludeTabsContent(true).execute(); List<Tab> allTabs = getAllTabs(doc); // Print the content from the first tab in the document. Tab firstTab = allTabs.get(0); // Get the DocumentTab from the generic Tab. DocumentTab documentTab = firstTab.getDocumentTab(); System.out.println( readStructuralElements(documentTab.getBody().getContent())); }
发出更新第一个标签页的请求
以下代码示例部分展示了如何定位 Request
中的特定标签页。此代码基于插入、删除和移动文本指南中的示例。
Java
/** Inserts text into the first tab of the document. */ static void insertTextInFirstTab(Docs service, String documentId) throws IOException { // Get the first tab's ID. Document doc = service.documents().get(documentId).setIncludeTabsContent(true).execute(); Tab firstTab = doc.getTabs().get(0); String tabId = firstTab.getTabProperties().getTabId(); List<Request>requests = new ArrayList<>(); requests.add(new Request().setInsertText( new InsertTextRequest().setText(text).setLocation(new Location() // Set the tab ID. .setTabId(tabId) .setIndex(25)))); BatchUpdateDocumentRequest body = new BatchUpdateDocumentRequest().setRequests(requests); BatchUpdateDocumentResponse response = docsService.documents().batchUpdate(DOCUMENT_ID, body).execute(); }