2017-07-25 6 views
0

リッチテキストコンテンツコントロールのリストと単一の文字列を引数とし、一致するすべてのコンテンツコントロールの内容をこの文字列に置き換える関数を作成しようとしています。どのようにword-jsを介して膨大な数のコンテンツコントロールのテキストを置き換えますか?

これは少量のコンテンツコントロールでは機能しますが、膨大な量のドキュメントでは失敗します。私は700タイトル以上のコンテンツコントロールを持つドキュメントを個別のタイトルで扱わなければなりません。この場合、コードは最初の66X CCを置き換え、GeneralExceptionで中止します。私は、これが膨大な量のコンテンツコントロールのせいだと仮定しています。私はこれらすべてのCC(GeneralException)のバインディングを登録しようとすると、同様の問題が発生しています。しかしこれは別の話題です。

私はこの問題を回避するために、.sync()ごとの変更量を制限し、CCをループして、必要な数のループを実行しました。しかし、office-jsの非同期性のために、これは簡単ではありません。私はこれまでjavascript-async-promise-programmingについてよく知らない。しかし、これは私が思いついたものです:

function replaceCCtextWithSingleString (CCtitleList, string) { 
    var maxPerBatch = 100; 

    /* 
    * A first .then() block is executed to get proxy objects for all selected CCs 
    * 
    * Then we would replace all the text-contents in one single .then() block. BUT: 
    * Word throws a GeneralException if you try to replace the text in more then 6XX CCs in one .then() block. 
    * In consequence we only process maxPerBatch CCs per .then() block 
    */ 
    Word.run(function (context) { 
     var CCcList = []; 

     // load CCs 
     for(var i = 0; i < CCtitleList.length; i++) { 
      CCcList.push(context.document.contentControls.getByTitle(CCtitleList[i]).load('id')); 
     } 

     return context.sync().then(function() { // synchronous 
      var CClist = []; 
      // aggregate list of CCs 
      for(var i = 0; i < CCcList.length; i++) { 
       if(CCcList[i].items.length == 0) { 
        throw 'Could not find CC with title "'+CCtitleList[j]+'"'; 
       } 
       else { 
        CClist = CClist.concat(CCcList[i].items); 
       } 
      } 
      $('#status').html('Found '+CClist.length+' CCs matching the criteria. Started replacing...'); 
      console.log('Found '+CClist.length+' CCs matching the criteria. Started replacing...'); 

      // start replacing 
      return context.sync().then((function loop (replaceCounter, CClist) { 
       // asynchronous recoursive loop 
       for(var i = 0; replaceCounter < CClist.length && i < maxPerBatch; i++) { // loop in loop (i does only appear in condition) 
        // do this maxPerBatch times and then .sync() as long as there are still unreplaced CCs 
        CClist[replaceCounter].insertText(string, 'Replace'); 
        replaceCounter++; 
       } 

       if(replaceCounter < CClist.length) return context.sync() // continue loop 
        .then(function() { 
         $('#status').html('...replaced the content of '+replaceCounter+' CCs...'); 
         return loop(replaceCounter, numCCs); 
        }); 
       else return context.sync() // end loop 
        .then(function() { 
         $('#status').html('Replaced the content of all CCs'); 
        }); 
      })(0, CClist)); 
     }); 
    }).catch(function (error) { 
     $('#status').html('<pre>Error: ' + JSON.stringify(error, null, 4) + '</pre>'); 
     console.log('Error: ' + JSON.stringify(error, null, 4)); 
     if (error instanceof OfficeExtension.Error) { 
      console.log('Debug info: ' + JSON.stringify(error.debugInfo, null, 4)); 
     } 
     throw error; 
    }); 
} 

しかし...それは動作していません。これは最初の100CCを置き換えて停止します。例外なく、何もせずに、失敗することなく。 return loop(replaceCounter, CClist);は実行されておらず、理由はわかりません。デバッガでこの行に入ると、私はoffice-jsコードのどこかで私を投げます。

提案がありますか?

編集:

私はフアンBalmoriの提案に基づいて、私のコードを更新し、それが魅力のように動作します。

function replaceCCtextWithSingleString_v1_1 (CCtitleList, string) { 
    Word.run(function (context) { 
     var time1 = Date.now(); 

     // load the title of all content controls 
     var CCc = context.document.contentControls.load('title'); 

     return context.sync().then(function() { // synchronous 
      // extract CC titles 
      var documentCCtitleList = []; 
      for(var i = 0; i < CCc.items.length; i++) { documentCCtitleList.push(CCc.items[i].title); } 

      // check for missing titles and replace 
      for(var i = 0; i < CCtitleList.length; i++) { 
       var index = documentCCtitleList.indexOf(CCtitleList[i]); 
       if(index == -1) { // title is missing 
        throw 'Could not find CC with title "'+CCtitleList[i]+'"'; 
       } 
       else { // replace 
        CCc.items[index].insertText(string, 'Replace'); 
       } 
      } 

      $('#status').html('...replacing...'); 

      return context.sync().then(function() { 
       var time2 = Date.now(); 
       var tdiff = time2-time1; 
       $('#status').html('Successfully replaced all selected CCs in '+tdiff+' ms'); 
      }); 
     }); 
    }).catch(function (error) { 
     $('#status').html('<pre>Error: ' + JSON.stringify(error, null, 4) + '</pre>'); 
     console.log('Error: ' + JSON.stringify(error, null, 4)); 
     if (error instanceof OfficeExtension.Error) { 
      console.log('Debug info: ' + JSON.stringify(error.debugInfo, null, 4)); 
     } 
    }); 
} 

それはまだ完了して13995ミリ秒かかりますが、少なくともそれが動作:-)

どのようなアイデアが、GeneralExceptionを引き起こしていましたか?

私はスピードの問題に関する新しい質問を投稿:What is the fastest way of replacing the text of many content controls via office-js?

答えて

1

いい質問を..私は長い時間前にいくつかのPERFテストを行なったし、私は、ドキュメント内の複数10Kコンテンツコントロールを変更することができました。 700とあなたは大丈夫です。 リストをあらかじめ入力する必要はないのですが、それは必要ではありません。実際には2倍のコレクションを実際にナビゲートしています。あなたはコレクションを横断しながら文字列の比較を行うことができます!

ここでは例を示しますが、仮想テストタグが "test"の700コンテンツコントロールドキュメントで簡単にテストしました。

私はできました 1.比較するテキストとその文字列を比較します(文字列) 2.条件が真であれば値を変更します。

操作を完了するまでに5134ミリ秒かかりましたが、ここにコードがあります。私はそれがかなり受け入れられると思います。

希望すると便利です。

function perfContentControls() { 
 
     var time1 = Date.now(); // lets see in how much time we complete the operation :) 
 
     var CCs =0 
 
     Word.run(function (context) { 
 
      var myCCs = context.document.body.contentControls.getByTag("test"); 
 
      context.load(myCCs); 
 
      return context.sync() 
 
      .then(function() { 
 
       CCs = myCCs.items.length 
 
       for (var i = 0; i < CCs; i++) { 
 
        if (myCCs.items[i].text == "new text 3") // you can check the cc content and if needed replace it.... 
 
         myCCs.items[i].insertText("new text 4", "replace"); 
 
       
 
       } 
 

 
       return context.sync() 
 
       .then(function() { 
 
        var time2 = Date.now(); 
 
        var diff = time2 - time1; 
 
        console.log("# of CCs:" + CCs + " time to change:" + diff + "ms"); 
 
       }) 
 
      }) 
 
      .catch(function (er) { 
 
       console.log(er.message); 
 

 
      }) 
 

 
     }) 
 

 
    }

+0

次のステップでは、タイトルに基づいて、これらのすべてのための個々のコンテンツを提供するために、する必要がありますので、私は、タイトルによって個々のコンテンツコントロールにアクセスする必要があります。私はあなたの提案に基づいて私の機能を再現しようとすると、変更時間を計算し、私のポストを更新します。 –

関連する問題