2017-07-25 117 views
0

我正在嘗試編寫一個函數,它將Rich Text Content Controls和一個字符串列表作爲參數,並用此字符串替換所有匹配的內容控件的內容。如何通過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; 
    }); 
} 

但是...它不工作。它取代了前100個CC,然後停止。沒有失敗,沒有例外或任何東西。 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次不適合perf的收集。您可以在遍歷集合時進行字符串比較!

下面是一個例子,我只是用一個假設的「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

我有標題來訪問個人內容的控制,因爲下一個步驟應該是,爲所有這些提供個性化的內容,基於標題。我會嘗試根據您的建議重新創建我的功能,計算更改時間並更新我的帖子。 –