【问题标题】:Google Docs API Batch Update - multiple updates to same template file?Google Docs API 批量更新 - 对同一模板文件的多次更新?
【发布时间】:2021-11-17 20:10:07
【问题描述】:

我正在尝试使用 Google Docs API 根据 JSON 文件中的值自动生成文档。

我创建了一个模板 Google Doc,其结构如下:

I went to the shop and bought the following item: {{foodtype}}. 

It cost {{price}}.

JSON 看起来像这样:


{
'food':'apples",
'price':'10'
}

因此,使用 Google Docs replaceAllText 方法,我可以使用 Python 脚本来更新文档,如下所示:

def update_doc(food_json,docs)
    

 requests=[
        {
            'replaceAllText': {
                'containsText': {
                    'text': '{{foodtype}}',
                    'matchCase': 'true'
                },
                'replaceText': 'food_json['food']',
            }},]

   

 doc_id = 'xxxxxxxxxxxxx'
 result = docs.documents().batchUpdate(documentId=doc_id, body={'requests': requests}).execute()

这非常有效。文档中的 {{foodtype}} 标记被 JSON 中的字符串替换。

我的问题是,当我想向文档添加多个更新时,我无法执行此操作。有时可能需要添加 5、10 甚至 50 个项目,因此无法手动向模板添加标签。

例如,如果我的 JSON 看起来像这样:

{
 {basket:
 {'food':'apples','price':'10'},
 {'food':'bread', 'price':'15'}
 {'food':'bananas', 'price': '5'}
 }
etc etc etc
}

我希望能够编写一个 for 循环来遍历 JSON 并为 JSON 中的每个项目编写报告,例如:

I went to the shop and bought the following item: apple. 
It cost 10 cents.

I went to the shop and bought the following item: bread.
It cost 15 cents.

I went to the shop and bought the following item: bananas.
It cost 5 cents.

代码如下所示:

requests = []

for f in food_json['basket']:
   requests.append(f)


requests=[
        {
            'replaceAllText': {
                'containsText': {
                    'text': '{{foodtype}}',
                    'matchCase': 'true'
                },
                'replaceText': 'f['food']',
            }},
            'replaceAllText': {
                'containsText': {
                    'text': '{{price}}',
                    'matchCase': 'true'
                },
                'replaceText': 'f['price']',
            }},

]

*Push the update to the Google docs*

但是这失败了,因为在 for 循环的第一次迭代中,匹配 {{foodtype}} 标记的文本被替换,然后在下一次迭代中没有任何内容可替换。

我不知道如何继续。

我以前使用过 MS Word 和很棒的 python-docx-template 库以这种方式发布文档。可以在 Word 模板中添加 Jinja 标签,然后直接在文档中使用 for 循环来实现我想要的,例如只需将这样的内容放入模板中即可:



{% for b in basket %}
I went to the shop and bought:

{{ b.food }}
The price was:

{{ b.price }}
{% endfor %}

这很好用,但我看不到如何使用 Google Docs API 和 Python 重现相同的结果。有什么建议吗?

【问题讨论】:

    标签: python google-docs google-docs-api


    【解决方案1】:

    我相信你的情况和目标如下。

    • 在您的情况下,一个文档中有几个相同的{{foodtype}} 文本。并且{{foodtype}}的个数和food的值是一样的。
    • 您想将第一个{{foodtype}} 替换为food 的第一个值。
    • 您想使用 googleapis for python 来实现这一点。

    如果我的理解是正确的,不幸的是,在当前阶段,当使用 Docs API 的replaceAllText 时,{{foodtype}} 的所有值在一个批处理请求中被替换为food 的第一个值。我认为这可能是您的问题的原因。

    流程:

    为了实现您在 python 中使用 Docs API 的目标,作为一种解决方法,我想提出以下流程。

    1. 在 Google 文档的文本中搜索 {{foodtype}}{{price}}
      • 在本例中,我使用了documents.get 方法。
    2. 将计数添加到{{foodtype}}{{price}} 的文本中。比如{{foodtype1}}{{price1}}{{foodtype2}}{{price2}}等等。
    3. 对于{{foodtype1}}{{price1}}{{foodtype2}}{{price2}}等文本,使用replaceAllText请求将每个值替换为它们。

    在此流程中,batchUpdate 请求用于一次调用。示例脚本如下。

    示例脚本:

    # Please set the values you want to replace.
    sample = {'basket': [
              {'food': 'apples', 'price': '10'},
              {'food': 'bread', 'price': '15'},
              {'food': 'bananas', 'price': '5'}
              ]}
    documentId = '###' # Please set your document ID.
    
    
    docs = build('docs', 'v1', credentials=creds)
    obj = docs.documents().get(documentId=documentId, fields='body').execute()
    content = obj.get('body').get('content')
    foodCount = 0
    priceCount = 0
    requests = []
    for c in content:
        if 'paragraph' in c:
            p = c.get('paragraph')
            for e in p.get('elements'):
                textRun = e.get('textRun')
                if textRun:
                    text = textRun.get('content')
                    if '{{foodtype}}' in text:
                        foodCount += 1
                        requests.append(
                            {
                                "replaceAllText": {
                                    "replaceText": sample['basket'][foodCount - 1]['food'],
                                    "containsText": {
                                        "text": '{{foodtype' + str(foodCount) + '}}',
                                        "matchCase": True
                                    }
                                }
                            }
                        )
                        requests.append({
                            "insertText": {
                                "location": {
                                    "index": e['startIndex'] + text.find('{{foodtype}}') + len('{{foodtype')
                                },
                                "text": str(foodCount)
                            }})
    
                    if '{{price}}' in text:
                        priceCount += 1
                        requests.append(
                            {
                                "replaceAllText": {
                                    "replaceText": sample['basket'][priceCount - 1]['price'],
                                    "containsText": {
                                        "text": '{{price' + str(priceCount) + '}}',
                                        "matchCase": True
                                    }
                                }
                            }
                        )
                        requests.append({
                            "insertText": {
                                "location": {
                                    "index": e['startIndex'] + text.find('{{price}}') + len('{{price')
                                },
                                "text": str(priceCount)
                            }})
    
    if requests != []:
        requests.reverse()
        docs.documents().batchUpdate(documentId=documentId, body={'requests': requests}).execute()
    

    注意:

    • 在您的问题中,以下值显示为示例值。

        {
         {basket:
         {'food':'apples','price':'10'},
         {'food':'bread', 'price':'15'}
         {'food':'bananas', 'price': '5'}
         }
        etc etc etc
        }
      
      • 但是,我认为这可能不正确。所以在我的示例脚本中,我使用了以下示例值。请根据您的实际情况修改每个值。

          sample = {'basket': [
                    {'food': 'apples', 'price': '10'},
                    {'food': 'bread', 'price': '15'},
                    {'food': 'bananas', 'price': '5'}
                    ]}
        
    • 在这个示例脚本中,作为解释我的解决方法的示例,搜索了 Google 文档中的段落。例如,当您要搜索表格中的文本时,请修改上述脚本。

    • 此示例脚本假设您已经能够使用 Docs API 获取和放置 Google Document 的值。请注意这一点。

    参考资料:

    【讨论】:

    • 感谢您非常有帮助和深入的回答@Tanaike。我稍后会尝试这个,如果它按预期工作,则标记为正确答案。
    • @ipconfuse 感谢您的回复。如果我的回答没有用,我深表歉意。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多