2

My first post here. My apologies in advance if I inadvertently break any rules.

Prerequisites:

Assume that I've created a Google service account, and obtained the credentials (JSON) file. I created a Google document, and I've its doc_ID available. My programming language is Python.

Problem:

Assume that I've a list of mixed-type of elements, e.g. (normal text, few nested list items, normal text, another nested list item), etc. See the example below:

my_list = [
    "This is the normal text line, without any itemized list format.",
    "* This is the outermost list item (number)",
    "* This is another outermost list item (number)",
    "  * This is a first-level indented list item (alpha)",
    "    * This is a second-level indented list item (roman)",
    "    * This is another second-level indented list item (roman)",
    "  * This is another first-level indented list item (alpha)",
    "This is the normal text line, without any itemized list format.",
    "* This is one more outermost list item (number)",
]

I want to write it to a Google document and obtain a mix of normal text paragraph, followed by a nested and properly indented numbered list, followed by a line of normal text paragraph, and finally, another nested list item (preferably continuing from my previous preset, but with the fresh numbering will also be acceptable).

I tried several approaches, and got the closest possible result with the suggestion of @tanaike in the following post. How do I indent a bulleted list with the Google Docs API

Here is my sample code:

    text_insert = ""
    for text in my_list:
        if text.startswith('* '):
            text_insert += text[2:] + '\n'
        elif text.startswith('  * '):
            text_insert += '\t' + text[4:] + '\n'
        elif text.startswith('    * '):
            text_insert += '\t\t' + text[6:] + '\n'
        else:
            text_normal = text + '\n'
            text_insert += text_normal
            end_index_normal = start_index + len(text_insert) + 1 - indent_corr
            start_index_normal = end_index_normal - len(text_normal)

    end_index = start_index + len(text_insert) + 1

    indented_requests = [
        {
            "insertText": {
                "text": text_insert,
                'location': {'index': start_index},
            }
        },
        {
            "createParagraphBullets": {
                'range': {
                    'startIndex': start_index,
                    'endIndex': end_index,  # Add 2 for the newline character
                },
                "bulletPreset": "NUMBERED_DECIMAL_ALPHA_ROMAN",
            }
        },
        {
            "deleteParagraphBullets": {
                'range': {
                    'startIndex': start_index_normal,
                    'endIndex': end_index_normal,
                },
            }
        },
    ]

    try:
        u_service.documents().batchUpdate(documentId=doc_id, body={'requests': indented_requests}).execute()
    except HttpError as error:
        print(f"An error occurred: {error}")

What I get in my Google document is the following:

enter image description here

However, my goal is the following (obtained after manual editing):

enter image description here

How can I achieve this? Any help will be greatly appreciated.

1
  • Warning: "Google document" = "night mare" Commented May 27, 2024 at 19:47

1 Answer 1

2

Modification points:

  • In your showing script, end_index_normal and start_index_normal are overwritten by another loop.
  • In the case of deleteParagraphBullets, only one character is selected.
  • Also, I guessed that in your situation, the last character might not be required to be included in createParagraphBullets.

When these points are reflected in your script, how about the following modification?

Modified script:

# Please set your variables.
doc_id = "###"
start_index = 1
indent_corr = 1


my_list = [
    "This is the normal text line, without any itemized list format.",
    "* This is the outermost list item (number)",
    "* This is another outermost list item (number)",
    "  * This is a first-level indented list item (alpha)",
    "    * This is a second-level indented list item (roman)",
    "    * This is another second-level indented list item (roman)",
    "  * This is another first-level indented list item (alpha)",
    "This is the normal text line, without any itemized list format.",
    "* This is one more outermost list item (number)",
]
text_insert = ""
deleteParagraphBullets = []
for text in my_list:
    if text.startswith('* '):
        text_insert += text[2:] + '\n'
    elif text.startswith('  * '):
        text_insert += '\t' + text[4:] + '\n'
    elif text.startswith('    * '):
        text_insert += '\t\t' + text[6:] + '\n'
    else:
        text_normal = text + '\n'
        text_insert += text_normal
        end_index_normal = start_index + len(text_insert) + 1 - indent_corr
        start_index_normal = end_index_normal - len(text_normal)
        deleteParagraphBullets.append({
            "deleteParagraphBullets": {
                'range': {
                    'startIndex': start_index_normal,
                    'endIndex': start_index_normal + 1,
                },
            }
        })
deleteParagraphBullets.reverse()
indented_requests = [
    {
        "insertText": {
            "text": text_insert,
            'location': {'index': start_index},
        }
    },
    {
        "createParagraphBullets": {
            'range': {
                'startIndex': start_index,
                'endIndex': start_index + len(text_insert),
            },
            "bulletPreset": "NUMBERED_DECIMAL_ALPHA_ROMAN",
        }
    }
] + deleteParagraphBullets
u_service.documents().batchUpdate(documentId=doc_id, body={'requests': indented_requests}).execute()

Testing:

When this script is run, the following result is obtained.

From

enter image description here

To

enter image description here

References:

Sign up to request clarification or add additional context in comments.

8 Comments

Perfect! Works flawlessly! Just one Q: What is the purpose of deleteParagraphBullets.reverse()? I also tried without reversing it, and it still produces the same result. I wish to accept this as the answer but my reputation of 11 does not allow me.
A follow-up Q: This approach prepares a single text string from all the given list elements (currently of only two formats, list item and normal text), and then prepares the request. If we've several kind of elements in the list, can we prepare a separate request for each element in a for loop, and then join all at the end to make one single request? A simple initial approach gives the numbering of all the indentations only with the outer-most numbers (no sub-numbering).
@Ait Paca About deleteParagraphBullets.reverse(), in the case of the deleting bullets, when it is run in ascending order, the indexes of other parts are changed. So, I used the descending order.
@Ait Paca About your new question, I would like to support you. But the issue of replying is new issue, and that is different from your question. So can you post it as new question? Because when your initial question is changed by comment, other users who see your question are confused. By posting it as new question, users including me can think of it. If you can cooperate to resolve your new issue, I'm glad. Can you cooperate to resolve your new question?
Thank you very much Sir! I've just posted my question, which is available at stackoverflow.com/q/78544321/25276165. Looking forward to your guidance/help.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.