如何通过word-js替换大量内容控件中的文本? [英] How replace the text in a huge number of content controls via word-js?

查看:99
本文介绍了如何通过word-js替换大量内容控件中的文本?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个函数,该函数以一个RTF内容控件列表和一个字符串作为参数,并用此字符串替换所有匹配的内容控件的内容.

I am trying to write a function which takes a list of Rich Text Content Controls and a single string as argument, and which replaces the content of all matching content controls with this string.

虽然这适用于较少的内容控件,但对于包含大量内容控件的文档却失败了.我必须处理带有700多个带有单独标题的内容控件的文档.在这种情况下,该代码仅替换前66X CC,然后中止并带有GeneralException.我认为这仅仅是由于大量的内容控件所致.当我尝试为所有这些CC注册绑定时,我遇到了类似的问题(GeneralException).但这是一个不同的话题.

While this works with a smaller amount of content controls, it fails with documents with a huge amount of them. I have to work with documents with over 700 Content Controls with individual titles. In this case, the code just replaces the first 66X CCs and then aborts with a GeneralException. I assume this is just due to the huge amount of content controls. I am having similar problems, when I try to register bindings for all these CCs (GeneralException). But this is a different topic.

我试图解决此问题,方法是限制每个.sync()的更改量并循环遍历CC,并根据需要执行尽可能多的循环.但是,由于office-js的异步特性,这并不是那么容易.到目前为止,我对javascript-async-promise-programming不太熟悉.但这是我想出的:

I tried to work around this problem, by limiting the amounts of changes per .sync() and looping through the CCs, performing as many loops as necessary. However, this is not that easy, due to the asynchronous nature of office-js. I am not very familiar with javascript-async-promise-programming so far. But this is what I have come up with:

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代码的某个位置.

However... it is not working. It replaces the first 100 CCs and then stops. Without a failure, without an exception or anything. The return loop(replaceCounter, CClist); is just not executed and I don't know why. If I try to step into this line in the debugger it throws me somewhere in the office-js code.

有什么建议吗?

我根据胡安·巴尔莫里(Juan Balmori)的建议更新了代码,并以此为魅力:

I updated my code based on the suggestions of Juan Balmori and it works as a charm:

    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毫秒才能完成,但至少可以正常工作:-)

It still takes 13995 ms to complete, but at least it works :-)

任何想法,是什么引起了GeneralException?

Any ideas, what was provoking the GeneralException though?

我发布了一个有关速度问题的新问题:

I posted a new question concerning the speed issue: What is the fastest way of replacing the text of many content controls via office-js?

推荐答案

好问题..很久以前,我进行了一些性能测试,并且能够更改文档中超过1万个内容控件. 700点就可以了. 不确定为什么要预先填写列表,这是不必要的,实际上您浏览的是该集合的2倍,这对性能不利.您可以在遍历集合时进行字符串比较!

Good Question.. I did some perf test long time ago and I was able to change more than 10k content controls in a document. with 700 you should be ok. Not sure why are you pre-filling a list, that is not needed, you are actually navigating 2 times the collection which is not good for perf. You can do the string comparison while traversing the collection!

这里是一个例子,我刚刚对一个700个内容控制文档(假设标签为"test")进行了快速测试.

Here is an example, I just did a quick test with a 700 content control document with a hypothetical tag of "test".

我能够 1.将他们的文字与您想要比较的文字(字符串)进行比较 2.如果条件为真,则更改该值.

I was able to 1. Compare their text against whatever you want to compare it (its a string) 2. Change the value if the condition is true.

完成该操作花费了5134毫秒,这是代码.我认为这完全可以接受.

It took 5134 milliseconds to complete the operation and here is the code. which I think its quite acceptable.

希望这会有所帮助!

 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);

           })

        })

    }

这篇关于如何通过word-js替换大量内容控件中的文本?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆