如何通过word-js替换海量内容控件中的文字?
How replace the text in a huge number of content controls via 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 代码中的某处。
有什么建议吗?
编辑:
我根据 Juan 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?
问得好.. 很久以前我做了一些性能测试,我能够更改文档中超过 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);
})
})
}
我正在尝试编写一个函数,它将富文本内容控件列表和单个字符串作为参数,并用该字符串替换所有匹配内容控件的内容。
虽然这适用于较少量的内容控件,但它无法处理包含大量内容控件的文档。我必须处理包含 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 代码中的某处。
有什么建议吗?
编辑:
我根据 Juan 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?
问得好.. 很久以前我做了一些性能测试,我能够更改文档中超过 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);
})
})
}