Google 表单的 JSON 数据是否缺少部分的项目 ID(这是提取跳过逻辑所必需的)?

Are Google Forms' JSON data missing Item Id's for sections (which is necessary for extracting skip logic)?

提问人:Hack-R 提问时间:8/31/2023 更新时间:10/23/2023 访问量:45

问:

Google 表单的数据可以通过 API 提取。使用 Python,我是这样拉的:

from __future__ import print_function

from apiclient import discovery
from httplib2 import Http
from oauth2client.service_account import ServiceAccountCredentials

import json

SCOPES = "https://www.googleapis.com/auth/forms.body.readonly"
DISCOVERY_DOC = "https://forms.googleapis.com/$discovery/rest?version=v1"

def get_google_form_data(form_id):
    creds = ServiceAccountCredentials.from_json_keyfile_name('service.json', SCOPES)
    http_auth = creds.authorize(Http())
    service = discovery.build('forms', 'v1', http=http_auth, discoveryServiceUrl=DISCOVERY_DOC, static_discovery=False)

    result = service.forms().get(formId=form_id).execute()
    return result

if __name__ == "__main__":
    form_id = 'xxx'
    json_data = get_google_form_data(form_id)

    with open("form_data.json", "w") as f:
        json.dump(json_data, f, indent=4)

测验的受访者可能会看到不同的问题,具体取决于他们的答案。在表单所有者的表单 Web 视图中,这些不同的部分被连续标记(“第 1 部分”、“第 2 部分”等),并且它们可以使用这些部分标签将值(也称为答案)与“跳过逻辑”相关联。例如,第一个答案可能链接到第 10 节,第二个答案选项可能链接到第 20 节。

在 JSON 数据中,它不是那些连续的用户友好标签,而是调用它,即“要转到的部分标题的项目 ID”。这将是简单明了的,但是 API(我可以找到)中没有任何内容可用于查找识别标题中的相应部分标题或问题。它具有“questionID”,它也是一个项目 ID,但这些 ID 与部分 ID 不同。goToSectionId

我认为我一定犯了一个错误,但是如果我使用任何值搜索原始 JSON,在每种情况下它们都只出现一次,因此它们不提供映射。如何提取跳过逻辑?goToSectionId

以下是 API 文档: https://developers.google.com/forms/api/reference/rest/v1/forms#QuestionItem

谷歌表格 API

评论

0赞 Babanana 8/31/2023
我想澄清一下你的问题,是否指的是你的JSON数据上的“标题”“描述”这样的标识符,而你得到的响应没有给出它?
0赞 Hack-R 8/31/2023
@Babanana我有标题和描述。但是,这些问题并不总是被问到,有些问题可能会以不同的顺序被问到。要知道要问哪个问题,以什么顺序(给定一些初始答案选项),我必须使用 goToSectionId 字段中的项目 ID 来查找下一个问题,具体取决于用户对上一个问题的回答。但是,没有要映射到 goToSectionId 值的部分 ID。
0赞 Babanana 8/31/2023
感谢您的回复。因此,要确认此 goToSectionId 是否作为端点上的参数被询问?你介意在这里分享端点吗?也许这样我们就能更好地理解您的问题。
0赞 Babanana 8/31/2023
我为之前的评论道歉。我认为对你来说更好的问题是你是否为你的代码使用一个库。
0赞 Hack-R 9/1/2023
@Babanana 仅上面代码片段中的库。不过,我认为 API 响应中缺少数据,因为我使用正则表达式搜索了整个原始 JSON 响应,发现 goToSectionId 中的 ID 值不会出现在其他任何地方。

答:

1赞 Luca Scandroglio 10/23/2023 #1

我遇到了一个非常相似的问题,我的意思是将条件逻辑归因于 ChoiceQuestion 类型。但是,在用 Java 开发了我的项目后,我发现的解决方案是不同的,所以尽管代码可能对您没有用,但请提取“概念”。

让我们从理论开始:我们需要创建一个格式正确的 JSON 请求来创建一个表单。在此 JSON 请求中,我们可以将选择的 itemId 属性分配给 Items,而不是满足于它们的自动归因。

即:

{
  "formId": null,
  "info":{
    "documentTitle":"Test1",
    "title":"Test 1"
  },
  "items":[{
    "itemId":"00000001",
    "questionItem": {
      "question":{
        "choiceQuestion":{
          "options":[{
            "value":"Option 1",
            "goToSectionId": "00000002"
          },
          {
            "value":"Option 2",
            "goToSectionId": "00000004"
          }],
          "type":"DROP_DOWN"
        },
        "questionId":"619ff865"}
    },
    "title":"Question 1"
  },
  {
    "description":"New Page descriptor",
    "itemId":"00000002",
    "pageBreakItem":{},
    "title":"ciao"
  },
    {
      "itemId":"00000003",
      "questionItem":{
        "question":{
          "choiceQuestion":{
            "options":[{
              "value":"Yes"
            },
              {
                "value":"No"
              }],
            "type":"RADIO"
          },
          "questionId":"73bcb98f"
        }},
      "title":"Question 2"
    },
    {
      "itemId":"00000004",
      "pageBreakItem":{
    },
      "title":"New Page descriptor"
    },
    {
      "itemId":"00000005",
      "questionItem":{
        "question":{
          "choiceQuestion":{
            "options":[{
              "value":"Yes"
            },
              {
                "value":"No"
              }],
            "type":"RADIO"
          },
          "questionId":"73bcb98f"
        }},
      "title":"Question 3"
    },],
  "responderUri": null,
  "revisionId": null
}

请注意,上面的 JSON 包含三个问题和两个分页符。问题 1 的答案将激活跳过问题 2(第 00000003 项)或问题 3(第 00000005 项)的逻辑。

请注意,pageBreakItems 对应于问题 1 中的选项。

就我而言,这是困难的部分。注意到 Google 表单 API 和相关的 Java 库使用 BatchRequest,其中每个元素都是按顺序插入的,插入问题会返回错误,因为选项的 ID 与后续的 pageBreakitems尚未插入)之间没有对应关系。

就我而言,解决方案是提出 2 个不同的请求:

  1. 第一个插入所有元素和 PageBreakItems,但带有条件逻辑的问题除外 (Question1)

  2. 第二个插入带有条件逻辑的问题,如问题 1

例如,我附上我编写的 Java 方法:

 private void publishForm(Form form, CustomForm customForm) throws IOException {
        BatchUpdateFormRequest batchRequest = new BatchUpdateFormRequest();
        List<Request> requests = new ArrayList<>();
        List<Request> goToSectionIdTypeRequest = new ArrayList<>();
        Integer counter = 0;

        for(CustomItem item : customForm.getItems()){
            Request request = new Request();
            request.setCreateItem(new CreateItemRequest());
            request.getCreateItem().setLocation(new Location());
            request.getCreateItem().setItem(item.getItem());
            request.getCreateItem().getLocation().setIndex(counter);

            /*
            * If the element is a dropdown it can have also an goToSectionId parameter:
            * in this case, it must be pushed inside the form in a second time
            */
            if (item.getQuestionItem() != null) {
                if (item.getQuestionItem().getQuestion().getChoiceQuestion() != null) {
                    if (item.getQuestionItem().getQuestion().getChoiceQuestion().getType() != null) {
                        String choiceType = item.getQuestionItem().getQuestion().getChoiceQuestion().getType();
                        if (choiceType.equals(ChoiceType.DROPDOWN.label)) {
                            if (item.getQuestionItem().getQuestion().getChoiceQuestion().getOptions().get(1).getGoToSectionId() != null) {
                                goToSectionIdTypeRequest.add(request);
                                continue;
                            }
                        }
                    }
                }
            }

            requests.add(request);
            counter++;
        }
        batchRequest.setRequests(requests);
        this.formservice.forms().batchUpdate(form.getFormId(), batchRequest).setAccessToken(token).execute();

        batchRequest.setRequests(goToSectionIdTypeRequest);
        this.formservice.forms().batchUpdate(form.getFormId(), batchRequest).setAccessToken(token).execute();

它并不优雅,但它有效。

我仍然随时为您服务,希望您能解决您的问题。

谢谢。

评论

1赞 Hack-R 11/6/2023
谢谢,卢卡。由于自提出问题以来已经过去了很长时间,我无法再尝试应用您的解决方案。因此,我在不接受的情况下投了赞成票。
0赞 Luca Scandroglio 11/6/2023
没问题,兄弟。