0
votes

I have a Google Docs document with a PARAGRAPH followed by a TABLE followed by a TABLE. Visually there is a PARAGRAPH between the two TABLEs. Programatically, however, using the following code, the run log demonstrates that there is no PARAGRAPH, viz

[1] PARAGRAPH {'LEFT_TO_RIGHT' : true, 'LINE_SPACING' : 1.15, 'SPACING_AFTER' : 0, 'SPACING_BEFORE' : 0, 'INDENT_FIRST_LINE' : 0, 'INDENT_END' : 0, 'INDENT_START' : 0} 
[1/1] TEXT {} perth influencer
[2] TABLE {'BORDER_WIDTH' : 1, 'BORDER_COLOR' : '#000000'} 
[3] TABLE {'BORDER_WIDTH' : 1, 'BORDER_COLOR' : '#000000'} Keyword Research Volume
...

According to the Google Apps Script documentation for appendTable:

This method will also append an empty paragraph after the table, since Google Docs documents cannot end with a table.

This paragraph can be seen with the eyes but the script as it stands cannot "see" it. That is, stepping through the child elements of the document's body fails to detect the presence of the automatically-inserted paragraph. This is a problem because I want to reduce the point size of that paragraph.

This may be a known limitation of Google Docs via Google Apps Script. Or it may be my bad code, so below are the functions that I base my assertion on. They do nothing other than report on what they find but even so, maybe I'm missing something.

The output above was generated by coding LogChildren with a parameter of type GoogleAppsScript.Document.Body and referring to the body of the generated document.

String.prototype.quoted = function () {
  return  "'" + this.replace(/'/g,"\\'") + "'";
}

Number.prototype.quoted = function () {
  return String(this);
}

Boolean.prototype.quoted = function () {
    return this ? "true" : "false";
}

function getInnerText(child) {
    switch (child.getType().toString()) {
        case "BODY_SECTION":
            return child.asBody().getText();
            break;
        case "EQUATION":
            return child.asEquation().getText();
            break;
        case "EQUATION_FUNCTION":
            return child.asEquationFunction().getText();
            break;
        case "FOOTER_SECTION":
            return child.asFooterSection().getText();
            break;
        case "FOOTNOTE_SECTION":
            return child.asFootnoteSection().getText();
            break;
        case "HEADER_SECTION":
            return child.asHeaderSection().getText();
            break;
        case "LIST_ITEM":
            return child.asListItem().getText();
            break;
        case "PARAGRAPH":
            return "";
            break;
        case "TABLE":
            return child.asTable().getText();
            break;
        case "TABLE_CELL":
            return child.asTableCell().getText();
            break;
        case "TABLE_OF_CONTENTS":
            return child.asTableOfContents().getText();
            break;
        case "TABLE_ROW":
            return child.asTableRow().getText();
            break;
        case "TEXT":
            return child.asText().getText();
            break;
        case "PAGE_BREAK":
            return "";
            break;
        case "INLINE_IMAGE":
            return child.asInlineImage().getLinkUrl();
            break;
        default:
            return child.asText().getText();
            break;
    }
}
function getStyles(child) {
    const attribs = child.getAttributes();
    const attribList = [];
    for (let att in attribs) {
        try {
            if (null !== attribs[att])
                attribList.push(att.quoted() + " : " + attribs[att].quoted());
        }
        catch (E) { }
    }
    return "{" + attribList.join(", ") + "}";
}
function LogChild(index, child) {
    Logger.log("[%s] %s %s %s", index, child.getType().toString(), getStyles(child), getInnerText(child));
}
function LogChildren(body) {
    function LogDeeper(cc, child) {
        const childCount = child.getNumChildren();
        for (let c = 0; c < childCount; c++) {
            LogChild(String(cc) + "/" + String(c + 1), child.getChild(c));
        }
    }
    const childCount = body.getNumChildren();
    for (let c = 0; c < childCount; c++) {
        const child = body.getChild(c);
        LogChild(String(c + 1), child);
        if (isParagraph(child)) {
            LogDeeper(c + 1, child.asParagraph());
        }
        else if (isListItem(child)) {
            LogDeeper(c + 1, child.asListItem());
        }
    }
}
function isPageBreak(elem) {
    return elem.getType() === DocumentApp.ElementType.PAGE_BREAK;
}
function isText(elem) {
    return elem.getType() === DocumentApp.ElementType.TEXT;
}
function isParagraph(elem) {
    return elem.getType() === DocumentApp.ElementType.PARAGRAPH;
}
function isListItem(elem) {
    return elem.getType() === DocumentApp.ElementType.LIST_ITEM;
}
function isTable(elem) {
    return elem.getType() === DocumentApp.ElementType.TABLE;
}
1
I have to apologize for my poor English skill. Unfortunately, I cannot understand about it doesn't not appear to be addressable. Can I ask you about addressable you expect? And also, can I ask you about the detail of your issue and your script? - Tanaike
since Google Docs documents cannot end with a table. That would simply mean there needs to be a table at the very end of your document and not between the tables. - TheMaster
@Tanaike I have attempted to clarify my description - bugmagnet
@bugmagnet Check the docs-api tester and see if there really is a paragraph between the tables. Preferably post the retrieved json here. - TheMaster
Thank you for replying. Although I'm not sure whether I could correctly understand about your question, if your situation is the same with this, it might be required to use Google Docs API. If I misunderstood about it, I apologize. - Tanaike

1 Answers

2
votes

Use 's Document#get to retrieve the document structure and if there is a intervening paragraph recorded between the two tables, issue UpdateParagraphStyleRequest to modify that paragraph.

You can access the api from apps script through Advanced Google services