0

I would like to copy the content of one google doc to another. The content includes text, tables and images.

My code copies the text and the tables. However, whatever is contained in table cells is not copied.

I made a simplified version of the code and single document accessible here: https://docs.google.com/document/d/1hcQzBuMA6E15u8VtW2lWGL7XCcU3qVsDhn-5jiznQP4/edit?usp=sharing.

The code simply copy-pastes the content of the google document which includes a table containing a table/images. The same problem occurs. The content of the cell is not copied. see screenshot

Here is the simplified version of the code:

function test() {
  
  // Make Copy of template file
  doc = DocumentApp.getActiveDocument();
  body =doc.getBody();
  

  
  /// Copy elements from source file to target file one bich one
  var totalElements = body.getNumChildren();
  var types = new Array;
  
  for( var iel = 0; iel < totalElements; iel++ ) {
     current_body = doc.getBody();
    var element = body.getChild(iel).copy();
    var type = element.getType();
    types.push(type);
    
    switch(type){
      case DocumentApp.ElementType.PARAGRAPH:
        body.appendParagraph(element);
        break;
      case DocumentApp.ElementType.TABLE:
        var newTable =body.insertTable( body.getNumChildren()-1, element );
        CopyTableCellByCell( element, newTable );
        break;
      case DocumentApp.ElementType.LIST_ITEM:
        body.appendListItem(element);
        break;
      case DocumentApp.ElementType.INLINE_IMAGE:
        body.appendImage(element); 
        break;
        
    }
  }
  doc.saveAndClose();
}

// recursive function that replaces each cell by first clearing it and Copying the content from the original table
function CopyTableCellByCell( srcTable, dstTable ) {
  var numRows = srcTable.getNumRows();
  var srcRow, numCells, dstCell, icell;
  var types = new Array;
  
  for ( var irow = 0; irow < numRows; irow++ ) {// EACH ROW
    srcRow = srcTable.getRow( irow );
    dstRow = dstTable.getRow( irow );
    numCells = srcRow.getNumCells();
    
    for ( icell = 0; icell < numCells; icell++ ) { // EACH CELL
      dstCell = dstRow.getCell( icell );
      dstCell.clear();
      var srcCell = srcTable.getCell( irow, icell );
      var numCellChildren = srcCell.getNumChildren(); // ==> outputs 1 paragraph child instead of a paragraph and a table.
      
      
      for ( var ich = 0; ich < numCellChildren; ich++ ) { // EACH CHILD
        var cellChild = srcCell.getChild( ich );
        var childCopy = cellChild.copy();
        var type = childCopy.getType();
        types.push(type);


        switch( type ){
            
          case DocumentApp.ElementType.PARAGRAPH:
            dstCell.insertParagraph( ich, childCopy );
            break;
            
          case DocumentApp.ElementType.LIST_ITEM:
            var atts    = childCopy.getAttributes();
            var newListItem = dstCell.insertListItem( ich, childCopy );
            newListItem.setAttributes( atts );
            break;
            
          case DocumentApp.ElementType.TABLE:

            var newTable = dstCell.insertTable( ich, childCopy );
            CopyTableCellByCell( cellChild, newTable );
            break;
            
          case DocumentApp.ElementType.INLINE_IMAGE:
            var parpar = childCopy.getParent();
            var ttt = parpar.getType();
            destImg = parpar.insertInlineImage(l, childCopy.getBlob()); 
            dstImg.setWidth(childCopy.getWidth());
            dstImg.setHeight(childCopy.getHeight());
            break;

        }
        
      }

    }
  }
}

Thanks for your help.

karin m
  • 1
  • 1
  • Thank you for replying. I noticed your comment. I'm sorry. I couldn't suppose that a table is included in the table. I updated my answer. Could you please confirm it? Although in my environment, I could confirm that this modified script worked when the added image in your question was used as the sample situation, if this didn't work in your environment, I'm sorry. By the way, could you please don't post your comment as an answer? – Tanaike Dec 23 '18 at 03:15
  • Thank you Tanaike. Sorry, I am new to Stackoverflow and realise now that I should have answered using a comment. I will check out your new code and let you know if it works right asap. Thank you so much for your help! – karin m Dec 23 '18 at 13:14
  • No problem. Thank you for your response. If your issue was not resolved and you want to add more information, please add it to your question using the edit button. By this, users can see your added information. – Tanaike Dec 23 '18 at 23:38

2 Answers2

1

How about this modification? I have experienced the same situation with you. At that time, I used this workaround. I think that there might be several solutions for your situation. So please think of this as one of them.

Modification points:

  • In the case that a table is copied, when there are the cells including images, it copies the images from source table to the target table. By this, the image can be seen. The flow is as follows.
    1. Copy the source table to the target.
    2. Retrieve paragraphs in a cell.
    3. Retrieve the image.
    4. Delete image from the target cell.
    5. Copy image from the source cell to the target cell.

Modified script:

Please modify as follows.

From:
else if( type == DocumentApp.ElementType.TABLE){
  body.appendTable(element);
}
To:
else if( type == DocumentApp.ElementType.TABLE){
  var dstTable = body.appendTable(element);
  var srcTable = element.asTable();
  var row = srcTable.getNumRows();
  for (var i = 0; i < row; i++) {
    var col = srcTable.getRow(i).getNumCells();
    for (var j = 0; j < col; j++) {
      var cell = srcTable.getCell(i, j);
      var c1 = cell.getNumChildren();
      for (var k = 0; k < c1; k++) {
        var paragraph = cell.getChild(k).asParagraph();
        var c2 = paragraph.getNumChildren();
        for (var l = 0; l < c2; l++) {
          var child = paragraph.getChild(l);
          var t = child.getType();
          if (t === DocumentApp.ElementType.INLINE_IMAGE) {
            var srcImg = child.asInlineImage();
            var dstParagraph = dstTable.getCell(i, j).getChild(k).asParagraph().clear();
            var dstImg = dstParagraph.insertInlineImage(l, srcImg.getBlob());
            dstImg.setWidth(srcImg.getWidth());
            dstImg.setHeight(srcImg.getHeight());
          }
        }
      }
    }
  }
}

References:

Although in my environment, I could confirm that this modified script worked when the image in your question was used as the sample situation, if this didn't work in your environment, I'm sorry.

Edit 1:

For your added situation, please modify your script as follows.

From:

else if( type == DocumentApp.ElementType.TABLE){
  body.appendTable(element);
}

To:

else if( type == DocumentApp.ElementType.TABLE){
  var dstTable = body.appendTable(element);
  var srcTable = element.asTable();
  copyTable(srcTable, dstTable);
}

And please add a following function.

function copyTable(srcTable, dstTable) {
  var row = srcTable.getNumRows();
  for (var i = 0; i < row; i++) {
    var col = srcTable.getRow(i).getNumCells();
    for (var j = 0; j < col; j++) {
      var cell = srcTable.getCell(i, j);
      var c1 = cell.getNumChildren();
      for (var k = 0; k < c1; k++) {
        var ty = cell.getChild(k).getType();
        if (ty === DocumentApp.ElementType.TABLE) {
          srcTable = cell.getChild(k).asTable();
          dstTable = dstTable.getCell(i, j).getChild(k).asTable();
          return copyTable(srcTable, dstTable);
        } else {
          var paragraph = cell.getChild(k).asParagraph();
          var c2 = paragraph.getNumChildren();
          for (var l = 0; l < c2; l++) {
            var child = paragraph.getChild(l);
            var t = child.getType();
            if (t === DocumentApp.ElementType.INLINE_IMAGE) {
              var srcImg = child.asInlineImage();
              var dstParagraph = dstTable.getCell(i, j).getChild(k).asParagraph().clear();
              var dstImg = dstParagraph.insertInlineImage(l, srcImg.getBlob());
              dstImg.setWidth(srcImg.getWidth());
              dstImg.setHeight(srcImg.getHeight());
            }
          }
        }
      }
    }
  }
}

Edit 2:

For your added situation, please modify your script as follows.

From:

else if( type == DocumentApp.ElementType.TABLE){
  body.appendTable(element);
}

To:

else if( type == DocumentApp.ElementType.TABLE){
  var dstTable = body.appendTable(element);
  var srcTable = element.asTable();
  copyTable(srcTable, dstTable);
}

And please add a following function.

function copyTable(srcTable, dstTable) {
  var row = srcTable.getNumRows();
  for (var i = 0; i < row; i++) {
    var col = srcTable.getRow(i).getNumCells();
    for (var j = 0; j < col; j++) {
      var cell = srcTable.getCell(i, j);
      var c1 = cell.getNumChildren();
      for (var k = 0; k < c1; k++) {
        var ty = cell.getChild(k).getType();
        if (ty === DocumentApp.ElementType.TABLE) {
          srcTable = cell.getChild(k).asTable();
          dstTable = dstTable.getCell(i, j).getChild(k).asTable();
          return copyTable(srcTable, dstTable);
        } else {
          var paragraph = cell.getChild(k).asParagraph();
          var c2 = paragraph.getNumChildren();
          for (var l = 0; l < c2; l++) {
            var child = paragraph.getChild(l);
            var t = child.getType();
            if (t === DocumentApp.ElementType.INLINE_IMAGE) {
              var srcImg = child.asInlineImage();
              var dstParagraph = dstTable.getCell(i, j).getChild(k).asParagraph();
              dstParagraph.getChild(l).asInlineImage().removeFromParent();
              var dstImg = dstParagraph.insertInlineImage(l, srcImg.getBlob());
              dstImg.setWidth(srcImg.getWidth());
              dstImg.setHeight(srcImg.getHeight());
            }
          }
        }
      }
    }
  }
}
Tanaike
  • 181,128
  • 11
  • 97
  • 165
  • I tested the code on the simplified google doc (https://docs.google.com/document/d/1hcQzBuMA6E15u8VtW2lWGL7XCcU3qVsDhn-5jiznQP4/edit) and the image and table contained in the cell are copied! However, the text that is on the same line than the image is not and the code gives an error message (Child index (1) must be less than the number of child elements (1). (line 69, file "Code")). I added a screenshot of the error message on the google doc. Thanks again for your help – karin m Dec 23 '18 at 13:35
  • I solved the error message by removing .clear() but now the image gets copied 3 times ... – karin m Dec 23 '18 at 15:05
  • @karin m I'm really sorry for the inconvenience. I updated my answer. Could you please confirm it? In the updated script, [your added sample](https://docs.google.com/document/d/1hcQzBuMA6E15u8VtW2lWGL7XCcU3qVsDhn-5jiznQP4/edit#) is reflected. If your issue was not resolved yet, can you provide the sample you are using? I would like to confirm it. – Tanaike Dec 23 '18 at 23:30
  • @karin m Did my answer show you the result what you want? Would you please tell me about it? That is also useful for me to study. If this works, other people who have the same issue with you can also base your question as a question which can be solved. If you have issues for my answer yet, feel free to tell me. I would like to study to solve your issues. – Tanaike Dec 25 '18 at 22:58
0

The code is almost functioning. The last issue is that the text that is in line with the images does not get copied.

I now restructured the code with additional functions. copyContent() calls copyTable() calls copyCellChild()

copyCellChild(), the function that copies the children of the cells from a source cell to a target cell cause the errors.

copyCellChild() ignores text in line with images.

function copyContent() {
  
  // Make Copy of template file
  doc = DocumentApp.getActiveDocument();
  body =doc.getBody();
  
  
  /// Copy elements from source file to target file one bich one
  var totalElements = body.getNumChildren();
  var types = new Array;
  
  for( var iel = 0; iel < totalElements; iel++ ) {
    current_body = doc.getBody();
    var element = body.getChild(iel).copy();
    var type = element.getType();
    types.push(type);
    
    switch(type){
      case DocumentApp.ElementType.PARAGRAPH:
        body.appendParagraph(element);
        break;
      case DocumentApp.ElementType.TABLE:
        //var newTable =body.insertTable( body.getNumChildren()-1, element );
        //CopyTableCellByCell( element, newTable );
        var dstTable = body.appendTable(element);
        var srcTable = element.asTable();
        copyTable(srcTable, dstTable);
        break;
      case DocumentApp.ElementType.LIST_ITEM:
        body.appendListItem(element);
        break;
      case DocumentApp.ElementType.INLINE_IMAGE:
        body.appendImage(element); 
        break;
        
    }
  }
  doc.saveAndClose();
}

function copyTable(srcTable, dstTable) {
  
  var row = srcTable.getNumRows();
  
  for (var i = 0; i < row; i++) { // ROW
    var col = srcTable.getRow(i).getNumCells();
    
    for (var j = 0; j < col; j++) { // CELL
      
      var srcCell = srcTable.getCell(i, j);
      var c1 = srcCell.getNumChildren();
      var destCell = dstTable.getCell(i, j);
      
      for (var k = 0; k < c1; k++) { // CHILD
        copyCellChild(srcCell,destCell,k);        
      }
    }
  }
}


function copyCellChild(srcCell,destCell,k){
  
  var srcChild = srcCell.getChild(k);
  var destChild = destCell.getChild(k);
  var ty = srcChild.getType();
  
  switch(ty){
      
    case DocumentApp.ElementType.TABLE:
      srcTable = srcChild.asTable();
      dstTable = destChild.asTable();
      return copyTable(srcTable, dstTable);
      break;
      
    case DocumentApp.ElementType.INLINE_IMAGE:
      var srcImg = srcChild.asInlineImage();
      var dstParagraph = destChild.asParagraph();
      
      
      var dstImg = dstParagraph.insertInlineImage(l, srcImg.getBlob());
      dstImg.setWidth(srcImg.getWidth());
      dstImg.setHeight(srcImg.getHeight());
      break;
      
    case DocumentApp.ElementType.PARAGRAPH:
      var paragraph = srcChild.asParagraph();//
      var c2 = paragraph.getNumChildren();
      
      
      for (var l = 0; l < c2; l++) { // PARAGRAPH CHILDREN

        try{
          var srcParaChild = paragraph.getChild(l);
          var t = srcParaChild.getType();
          
          switch(t){
              
            case DocumentApp.ElementType.INLINE_IMAGE:
              
              var srcImg = srcParaChild.asInlineImage();
              var dstParagraph = destChild.asParagraph().clear();
              //var dstParagraph = destChild.asInlineImage().clear();//clear
              
              var dstImg = dstParagraph.insertInlineImage(l, srcImg.getBlob());
              dstImg.setWidth(srcImg.getWidth());
              dstImg.setHeight(srcImg.getHeight());
              dstImg.setLinkUrl(srcImg.getLinkUrl);
              break;
            case DocumentApp.ElementType.TEXT:
              //var srcTxt = srcChild.getText();
              //Logger.log(srcTxt);
              //var iii = 1;
              //destChild.asText().appendText(srcTxt);
              
          }
        }catch(e){// text in line with images
          var srcTxt = srcChild.getText();
          Logger.log(srcTxt);
          var iii = 1;
          destChild.asText().appendText(srcTxt);
          
        }
      }
  }
  
}

Here is the example google doc where you can run the function : https://docs.google.com/document/d/1hcQzBuMA6E15u8VtW2lWGL7XCcU3qVsDhn-5jiznQP4/edit#

karin m
  • 1
  • 1