我有一个word文档模板和一个CSV,我想用它进行邮件合并。
在word文档中,我的文本被<<>>包围,如果我想使用它来进行邮件合并,这与我的csv中的标头匹配。例如,我的word文档中有<<Salutation>>,csv中有字段名称谓。
是否有一种简单的方法可以将被<<>>包围的文本替换为对应于CSV中的标头的mailmerge字段?
到目前为止,我用于读取数据的代码是:
Microsoft.Office.Interop.Word.Application _wordApp = new Microsoft.Office.Interop.Word.Application();
Microsoft.Office.Interop.Word.Document oDoc = _wordApp.Documents.Add(@"C:\Eyre\Template.docx");
_wordApp.Visible = true;
oDoc.MailMerge.MainDocumentType = Microsoft.Office.Interop.Word.WdMailMergeMainDocType.wdFormLetters;
oDoc.MailMerge.OpenDataSource(@"C:\Eyre\CSV.csv", false, false, true);
oDoc.MailMerge.Destination = Microsoft.Office.Interop.Word.WdMailMergeDestination.wdSendToNewDocument;
oDoc.MailMerge.Execute(false);
Microsoft.Office.Interop.Word.Document oLetters = _wordApp.ActiveDocument;
oLetters.SaveAs2(@"C:\Eyre\letters.docx",
Microsoft.Office.Interop.Word.WdSaveFormat.wdFormatDocumentDefault);任何帮助都将不胜感激。
编辑
这似乎让一些人感到困惑。我有一个带有纯文本的word模板,比如问候语,我需要一个C#程序,它将用来自csv的合并字段替换这个纯文本。
发布于 2018-05-14 10:41:56
这里有一个C#版本的代码,用于将Word文档中的“占位符”替换为合并字段。(要获得VB版本的读者,请参见https://stackoverflow.com/a/50159375/3077495。)
我的代码使用了一个已经在运行的Word实例,所以您感兴趣的部分从foreach (Word.MailMergeDataField开始.
查找/替换操作在它们自己的过程ReplaceTextWithMergeField中,数据源字段的名称(如Word所看到的那样!)和搜索的目标范围被传递给它。
请注意,在此过程中,如何将角度括号对附加到数据字段名。
查找/替换操作是标准的,重新设置继续搜索数据字段名的Range对象有点不同,因为有必要获得合并字段之外的位置--在插入字段之后,范围在字段代码中。如果这还没有完成,Find可能会在“无限”的同一字段中结束。(注:在这种情况下,不是带有双角括号的。但是,如果有人使用没有它们的代码,那么就会出现问题。)
编辑:为了在Shape对象中找到和替换这些对象,必须分别循环这些对象。任何使用文本包装进行格式化的内容都位于文档的另一层,而不是Document.Content的一部分。我在第三个过程中修改了查找过程,以便搜索文档的ShapeRange,特别是测试文本框。
private void btnDataToMergeFields_Click(object sender, EventArgs e)
{
getWordInstance();
if (wdApp != null)
{
if (wdApp.Documents.Count > 0)
{
Word.Document doc = wdApp.ActiveDocument;
Word.Range rng = doc.Content;
Word.ShapeRange rngShapes = rng.ShapeRange;
if (doc.MailMerge.MainDocumentType != Word.WdMailMergeMainDocType.wdNotAMergeDocument)
foreach (Word.MailMergeDataField mmDataField in doc.MailMerge.DataSource.DataFields)
{
System.Diagnostics.Debug.Print(ReplaceTextWithMergeField(mmDataField.Name, ref rng).ToString()
+ " merge fields inserted for " + mmDataField.Name);
rng = doc.Content;
System.Diagnostics.Debug.Print(ReplaceTextWithMergeFieldInShapes(mmDataField.Name, ref rngShapes)
+ " mergefields inserted for " + mmDataField.Name);
}
}
}
}
//returns the number of times the merge field was inserted
public int ReplaceTextWithMergeField(string sFieldName, ref Word.Range oRng)
{
int iFieldCounter = 0;
Word.Field fldMerge;
bool bFound;
oRng.Find.ClearFormatting();
oRng.Find.Forward = true;
oRng.Find.Wrap = Word.WdFindWrap.wdFindStop;
oRng.Find.Format = false;
oRng.Find.MatchCase = false;
oRng.Find.MatchWholeWord = false;
oRng.Find.MatchWildcards = false;
oRng.Find.MatchSoundsLike = false;
oRng.Find.MatchAllWordForms = false;
oRng.Find.Text = "<<" + sFieldName + ">>";
bFound = oRng.Find.Execute();
while (bFound)
{
iFieldCounter = iFieldCounter + 1;
fldMerge = oRng.Fields.Add(oRng, Word.WdFieldType.wdFieldMergeField, sFieldName, false);
oRng = fldMerge.Result;
oRng.Collapse(Word.WdCollapseDirection.wdCollapseEnd);
oRng.MoveStart(Word.WdUnits.wdCharacter, 2);
oRng.End = oRng.Document.Content.End;
oRng.Find.Text = "<<" + sFieldName + ">>";
bFound = oRng.Find.Execute();
}
return iFieldCounter;
}
public int ReplaceTextWithMergeFieldInShapes(string sFieldName,
ref Word.ShapeRange oRng)
{
int iFieldCounter = 0;
Word.Field fldMerge;
bool bFound;
foreach (Word.Shape shp in oRng)
{
if (shp.Type == Office.MsoShapeType.msoTextBox)
{
Word.Range rngText = shp.TextFrame.TextRange;
rngText.Find.ClearFormatting();
rngText.Find.Forward = true;
rngText.Find.Wrap = Word.WdFindWrap.wdFindStop;
rngText.Find.Format = false;
rngText.Find.MatchCase = false;
rngText.Find.MatchWholeWord = false;
rngText.Find.MatchWildcards = false;
rngText.Find.MatchSoundsLike = false;
rngText.Find.MatchAllWordForms = false;
rngText.Find.Text = "<<" + sFieldName + ">>";
bFound = rngText.Find.Execute();
while (bFound)
{
iFieldCounter = iFieldCounter + 1;
fldMerge = rngText.Fields.Add(rngText, Word.WdFieldType.wdFieldMergeField, sFieldName, false);
rngText = fldMerge.Result;
rngText.Collapse(Word.WdCollapseDirection.wdCollapseEnd);
rngText.MoveStart(Word.WdUnits.wdCharacter, 2);
rngText.End = shp.TextFrame.TextRange.End;
rngText.Find.Text = sFieldName;
bFound = rngText.Find.Execute();
}
}
}
return iFieldCounter;
}发布于 2018-05-14 05:30:03
有许多方法取决于您更广泛的需求。如果您将根据Windows机器上简单/小任务的需要运行该工具,那么VBA/宏方法可能是最好的方法,因为您已经准备好了所需的东西。
另一种方法需要对DOCX进行更多的编码和理解,但是您可以在没有more库的机器上扩展和运行它。因为DocX是开放的和基于文本的,所以您可以解压缩它,处理XML内容并重新压缩。存在一些问题,因为XML并不简单。如果您正在这样做,使用Word合并字段比普通文本更好(对程序员来说),因为查找字段更简单。对于使用文档/模板的人来说,纯文本更好,因为他们不需要处理合并字段,但缺点是XML处理可能变得更加复杂。模板<<Salutation>>中的文本可能不容易找到XML --它可能被分割成几个部分。
另一个解决方案是使用类似Docmosis (一种商业产品-请注意我为Docmosis工作)的东西。优点是Docmosis可以完成替换和更复杂的需求(例如,条件结构和循环结构,PDF转换)。缺点是,您必须学习API并安装软件(或调用云),并将数据转换为传递给引擎的格式。
我希望这能帮上忙。
https://stackoverflow.com/questions/50294941
复制相似问题