2

書式設定されたテキストをある文書からコピーして、別の文書に貼り付けようとしています。1 つのドキュメント全体を取得し、Google App Script を介して別のドキュメントに追加したいと考えています。

呼び出しbody.getText()は私のユースケースを満たしていますが、テキストをフォーマットされていない文字列として取得します。

あるドキュメントから別のドキュメントに書式設定されたテキストをコピーできると便利です。

EDIT:アドバイスを受けて、私は現在さらにコードを書いています。他の回答にほぼ正確に従って、私はまだテキストだけを取得しており、フォーマットも取得していません。

  for(var i = 0; i < numElements; ++i) {
  var element = copyBody.getChild(i)
  var type = element.getType();
   if (type == DocumentApp.ElementType.PARAGRAPH)
   {
     var newElement = element.copy().asParagraph();
     newBody.appendParagraph(newElement); 
   }
   else if(type == DocumentApp.ElementType.TABLE)
   {
     var newElement = element.copy().asTable();
     newBody.appendTable(newElement); 
   }
   else if(type == DocumentApp.ElementType.LIST_ITEM)
   {     
     var newElement = element.copy().asListItem();
     newBody.appendListItem(newElement);
   }
    else{
    Logger.log("WRONG ELEMENT")    
    }
  }    
4

2 に答える 2

6

This answer covers it.

You need to iterate through the elements of the source document, appending each to the destination doc. You don't copy Text versions of paragraphs, etc., instead you copy the whole element including formatting etc.

Script

Since Documents now support programmable UI elements, here's a script based on Henrique's previous answer (above), that includes a Custom Menu to drive the merge of documents. You may optionally include page breaks between appended documents - useful if you are trying to create a multi-chapter document.

This script must be contained in a Document (or no UI for you)!

/**
 * The onOpen function runs automatically when the Google Docs document is
 * opened. 
 */
function onOpen() {
  DocumentApp.getUi().createMenu('Custom Menu')
      .addItem('Append Document','appendDoc')
      .addToUi();
}

/**
 * Shows a custom HTML user interface in a dialog above the Google Docs editor.
 */
function appendDoc() {
  // HTML for form is rendered inline here.
  var html =
      '<script>'
  +     'function showOutput(message) {'
  +       'var div = document.getElementById("output");'
  +       'div.innerHTML = message;'
  +     '}'
  +   '</script>'
  +   '<form id="appendDoc">'
  +     'Source Document ID: <input type="text" size=60 name="docID"><br>'
  +     'Insert Page Break: <input type="checkbox" name="pagebreak" value="pagebreak">'
  +     '<input type="button" value="Begin" '
  +       'onclick="google.script.run.withSuccessHandler(showOutput).processAppendDocForm(this.parentNode)" />'
  +   '</form>' 
  +   '<br>'
  +   '<div id="output"></div>'

  DocumentApp.getUi().showDialog(
    HtmlService.createHtmlOutput(html)
               .setTitle('Append Document')
               .setWidth(400 /* pixels */)
               .setHeight(150 /* pixels */));
}

/**
 * Handler called when appendDoc form submitted.
 */
function processAppendDocForm(formObject) {
  Logger.log(JSON.stringify(formObject));
  var pagebreak = (formObject.pagebreak == 'pagebreak');
  mergeDocs([DocumentApp.getActiveDocument().getId(),formObject.docID],pagebreak);
  return "Document appended.";
}

/**
 * Updates first document in list by appending all others.
 *
 * Modified version of Henrique's mergeDocs().
 * https://stackoverflow.com/a/10833393/1677912
 *
 * @param {Array} docIDs      Array of documents to merge.
 * @param {Boolean} pagebreak Set true if a page break is desired
 *                              between appended documents.
 */
function mergeDocs(docIDs,pagebreak) {
  var baseDoc = DocumentApp.openById(docIDs[0]);
  var body = baseDoc.getBody();

  for( var i = 1; i < docIDs.length; ++i ) {
    if (pagebreak) body.appendPageBreak();
    var otherBody = DocumentApp.openById(docIDs[i]).getBody(); 
    Logger.log(otherBody.getAttributes());
    var totalElements = otherBody.getNumChildren();
    var latestElement;
    for( var j = 0; j < totalElements; ++j ) {
      var element = otherBody.getChild(j).copy();
      var attributes = otherBody.getChild(j).getAttributes();
      // Log attributes for comparison
      Logger.log(attributes);
      Logger.log(element.getAttributes());
      var type = element.getType(); 
      if (type == DocumentApp.ElementType.PARAGRAPH) {
        if (element.asParagraph().getNumChildren() != 0 && element.asParagraph().getChild(0).getType() == DocumentApp.ElementType.INLINE_IMAGE) {
          var pictattr = element.asParagraph().getChild(0).asInlineImage().getAttributes();
          var blob = element.asParagraph().getChild(0).asInlineImage().getBlob();
          // Image attributes, e.g. size, do not survive the copy, and need to be applied separately
          latestElement = body.appendImage(blob);
          latestElement.setAttributes(clean(pictattr));
        }
        else latestElement = body.appendParagraph(element);
      }
      else if( type == DocumentApp.ElementType.TABLE )
        latestElement = body.appendTable(element);
      else if( type == DocumentApp.ElementType.LIST_ITEM )
        latestElement = body.appendListItem(element);
      else
        throw new Error("Unsupported element type: "+type);
      // If you find that element attributes are not coming through, uncomment the following
      // line to explicitly copy the element attributes from the original doc.
      //latestElement.setAttributes(clean(attributes));
    }
  }
}


/**
 * Remove null attributes in style object, obtained by call to
 * .getAttributes().
 * https://code.google.com/p/google-apps-script-issues/issues/detail?id=2899
 */
function clean(style) {
  for (var attr in style) {
    if (style[attr] == null) delete style[attr];
  }
  return style;
}

Edit: Adopted handling of inline images from Serge's answer, with handling of image size attributes. As the comments indicate, there have been problems with some attributes being snarfed in the append, thus the introduction of the clean() helper function and use of .setAttributes(). However, you'll note that the call to .setAttributes() is commented out; that's because it too has a side-effect that will remove some formatting. It's your choice about which annoyance you'd rather deal with.

于 2013-07-10T17:45:49.943 に答える
1

ここでは、Mogsdad スクリプトを少し改善して、インライン イメージもコピーします。

唯一の問題は、画像のサイズが変更された場合、コピーにこの新しいサイズが保持されず、画像が元のサイズで表示されることです...それを解決する方法が今のところわかりません。

function mergeDocs(docIDs,pagebreak) {
  var baseDoc = DocumentApp.openById(docIDs[0]);
  var body = baseDoc.getBody();

  for( var i = 1; i < docIDs.length; ++i ) {
    if (pagebreak) body.appendPageBreak();
    var otherBody = DocumentApp.openById(docIDs[i]).getBody();
    var totalElements = otherBody.getNumChildren();
    for( var j = 0; j < totalElements; ++j ) {
      var element = otherBody.getChild(j).copy();
      var type = element.getType(); 
      if (type == DocumentApp.ElementType.PARAGRAPH) {
        if (element.asParagraph().getNumChildren() != 0 && element.asParagraph().getChild(0).getType() == DocumentApp.ElementType.INLINE_IMAGE) {
          var blob = element.asParagraph().getChild(0).asInlineImage().getBlob();
          body.appendImage(blob);
        }
        else body.appendParagraph(element.asParagraph());
      }
      else if( type == DocumentApp.ElementType.TABLE )
        body.appendTable(element);
      else if( type == DocumentApp.ElementType.LIST_ITEM )
        body.appendListItem(element);
      else
        throw new Error("According to the doc this type couldn't appear in the body: "+type);
    }
  }
}

このドキュメント ID でテストできます: 1E6yoROb52QjICsEbGVXIBdz8KhdFU_5gimWlJUbu8DI

(実行成功 [合計実行時間 43.896 秒]) !!! 我慢して !

このコードはこの他の投稿からのものです

于 2013-07-10T21:23:45.750 に答える