gpt4 book ai didi

c# - 你如何在c#中邮件合并一个word文档

转载 作者:太空狗 更新时间:2023-10-30 00:14:12 25 4
gpt4 key购买 nike

我要实现的目标

在我的 c# 应用程序中,我想从我的应用程序中的数据生成一个报告(word 文档),我认为最好的方法是使用我的应用程序中的数据源执行类似邮件合并的操作。

我尝试过的

  1. 我试着按照这个 Mail Merge into word然而,这使用你需要支付的 GemBox
  2. 我曾尝试使用 Microsoft.Office.Interop.Word 但我失败了短暂的,当我不知道如何引用保存的模板文档时:

    Dictionary<string, string> MailMerge = new Dictionary<string, string>()
    {
    { "ID", "123" },
    { "Name", "Test" },
    { "Address1", "Test" },
    { "Address2", "Test" },
    { "Address3", "Test" },
    { "Address4", "Test" },
    { "PostCode", "Test" },
    { "Year End", "Test" },
    { "SicCode", "123" },
    };

    Document doc = new Document();
    doc.MailMerge.Execute(MailMerge);

总结

我正在寻找一些关于进一步研究的指导,因为我相信必须有一个“标准”的方法来做这件事。

最佳答案

无法相信第三方软件会为 Word 的界面功能收取数千美元的费用。我已经在我的项目中完美地解决了这个邮件合并问题——没有第三方,对 IIS 没有特殊要求,只需使用 OpenXML。因此,将这 4 个函数添加到您的项目中:

public static void dotx2docx(string sourceFile, string targetFile)
{
MemoryStream documentStream;
using (Stream tplStream = File.OpenRead(sourceFile))
{
documentStream = new MemoryStream((int)tplStream.Length);
CopyStream(tplStream, documentStream);
documentStream.Position = 0L;
}

using (WordprocessingDocument template = WordprocessingDocument.Open(documentStream, true))
{
template.ChangeDocumentType(DocumentFormat.OpenXml.WordprocessingDocumentType.Document);
MainDocumentPart mainPart = template.MainDocumentPart;
mainPart.DocumentSettingsPart.AddExternalRelationship("http://schemas.openxmlformats.org/officeDocument/2006/relationships/attachedTemplate",
new Uri(targetFile, UriKind.Absolute));

mainPart.Document.Save();
}
File.WriteAllBytes(targetFile, documentStream.ToArray());
}
public static void CopyStream(Stream source, Stream target)
{
if (source != null)
{
MemoryStream mstream = source as MemoryStream;
if (mstream != null) mstream.WriteTo(target);
else
{
byte[] buffer = new byte[2048];
int length = buffer.Length, size;
while ((size = source.Read(buffer, 0, length)) != 0)
target.Write(buffer, 0, size);
}
}
}
public static void Mailmerge(string templatePath, string DestinatePath, DataRow dr, DataColumnCollection columns)
{
try
{
dotx2docx(templatePath, DestinatePath);
}
catch //incase the server does not support MS Office Word 2003 / 2007 / 2010
{
File.Copy(templatePath, DestinatePath, true);
}
using (WordprocessingDocument doc = WordprocessingDocument.Open(DestinatePath, true))
{
var allParas = doc.MainDocumentPart.Document.Descendants<DocumentFormat.OpenXml.Wordprocessing.Text>();
Text PreItem = null;
string PreItemConstant = null;
bool FindSingleAnglebrackets = false;
bool breakFlag = false;
List<Text> breakedFiled = new List<Text>();
foreach (Text item in allParas)
{
foreach (DataColumn cl in columns)
{
//<Today>
if (item.Text.Contains("«" + cl.ColumnName + "»") || item.Text.Contains("<" + cl.ColumnName + ">"))
{
item.Text = item.Text.Replace("<" + cl.ColumnName + ">", dr[cl.ColumnName].ToString())
.Replace("«" + cl.ColumnName + "»", dr[cl.ColumnName].ToString());
FindSingleAnglebrackets = false;
breakFlag = false;
breakedFiled.Clear();
}
else if //<Today
(item.Text != null
&& (
(item.Text.Contains("<") && !item.Text.Contains(">"))
|| (item.Text.Contains("«") && !item.Text.Contains("»"))
)
&& (item.Text.Contains(cl.ColumnName))
)
{
FindSingleAnglebrackets = true;
item.Text = global::System.Text.RegularExpressions.Regex.Replace(item.Text, @"\<" + cl.ColumnName + @"(?!\w)", dr[cl.ColumnName].ToString());
item.Text = global::System.Text.RegularExpressions.Regex.Replace(item.Text, @"\«" + cl.ColumnName + @"(?!\w)", dr[cl.ColumnName].ToString());
}
else if //Today> or Today
(
PreItemConstant != null
&& (
(PreItemConstant.Contains("<") && !PreItemConstant.Contains(">"))
|| (PreItemConstant.Contains("«") && !PreItemConstant.Contains("»"))
)
&& (item.Text.Contains(cl.ColumnName))
)
{
if (item.Text.Contains(">") || item.Text.Contains("»"))
{
FindSingleAnglebrackets = false;
breakFlag = false;
breakedFiled.Clear();
}
else
{
FindSingleAnglebrackets = true;
}
if (PreItemConstant == "<" || PreItemConstant == "«")
{
PreItem.Text = "";
}
else
{
PreItem.Text = global::System.Text.RegularExpressions.Regex.Replace(PreItemConstant, @"\<" + cl.ColumnName + @"(?!\w)", dr[cl.ColumnName].ToString());
PreItem.Text = global::System.Text.RegularExpressions.Regex.Replace(PreItemConstant, @"\«" + cl.ColumnName + @"(?!\w)", dr[cl.ColumnName].ToString());
}
if (PreItemConstant.Contains("<") || PreItemConstant.Contains("«")) // pre item is like '[blank]«'
{
PreItem.Text = PreItem.Text.Replace("<", "");
PreItem.Text = PreItem.Text.Replace("«", "");
}
if (item.Text.Contains(cl.ColumnName + ">") || item.Text.Contains(cl.ColumnName + "»"))
{
item.Text = global::System.Text.RegularExpressions.Regex.Replace(item.Text, @"(?<!\w)" + cl.ColumnName + @"\>", dr[cl.ColumnName].ToString());
item.Text = global::System.Text.RegularExpressions.Regex.Replace(item.Text, @"(?<!\w)" + cl.ColumnName + @"\»", dr[cl.ColumnName].ToString());

}
else
{
item.Text = global::System.Text.RegularExpressions.Regex.Replace(item.Text, @"(?<!\w)" + cl.ColumnName + @"(?!\w)", dr[cl.ColumnName].ToString());
}
}
else if (FindSingleAnglebrackets && (item.Text.Contains("»") || item.Text.Contains(">")))
{
item.Text = global::System.Text.RegularExpressions.Regex.Replace(item.Text, @"(?<!\w)" + cl.ColumnName + @"\>", dr[cl.ColumnName].ToString());
item.Text = global::System.Text.RegularExpressions.Regex.Replace(item.Text, @"(?<!\w)" + cl.ColumnName + @"\»", dr[cl.ColumnName].ToString());
item.Text = global::System.Text.RegularExpressions.Regex.Replace(item.Text, @"^\s*\>", "");
item.Text = global::System.Text.RegularExpressions.Regex.Replace(item.Text, @"^\s*\»", "");
FindSingleAnglebrackets = false;
breakFlag = false;
breakedFiled.Clear();
}
else if (item.Text.Contains("<") || item.Text.Contains("«")) // no ColumnName
{

}
} //end of each columns
PreItem = item;
PreItemConstant = item.Text;
if (breakFlag
|| (item.Text.Contains("<") && !item.Text.Contains(">"))
|| (item.Text.Contains("«") && !item.Text.Contains("»"))
)
{
breakFlag = true;
breakedFiled.Add(item);
string combinedfiled = "";
foreach (Text t in breakedFiled)
{
combinedfiled += t.Text;
}
foreach (DataColumn cl in columns)
{
//<Today>
if (combinedfiled.Contains("«" + cl.ColumnName + "»") || combinedfiled.Contains("<" + cl.ColumnName + ">"))
{
//for the first part, remove the last '<' and tailing content
breakedFiled[0].Text = global::System.Text.RegularExpressions.Regex.Replace(breakedFiled[0].Text, @"<\w*$", "");
breakedFiled[0].Text = global::System.Text.RegularExpressions.Regex.Replace(breakedFiled[0].Text, @"<\w*$", "");

//remove middle parts
foreach (Text t in breakedFiled)
{
if (!t.Text.Contains("<") && !t.Text.Contains("«") && !t.Text.Contains(">") && !t.Text.Contains("»"))
{
t.Text = "";
}
}

//for the last part(as current item), remove leading content till the first '>'
item.Text = global::System.Text.RegularExpressions.Regex.Replace(item.Text, @"^\s*\>", dr[cl.ColumnName].ToString());
item.Text = global::System.Text.RegularExpressions.Regex.Replace(item.Text, @"^\s*\»", dr[cl.ColumnName].ToString());

FindSingleAnglebrackets = false;
breakFlag = false;
breakedFiled.Clear();
break;
}
}
}
}//end of each item
#region go through footer
MainDocumentPart mainPart = doc.MainDocumentPart;
foreach (FooterPart footerPart in mainPart.FooterParts)
{
Footer footer = footerPart.Footer;
var allFooterParas = footer.Descendants<Text>();
foreach (Text item in allFooterParas)
{
foreach (DataColumn cl in columns)
{
if (item.Text.Contains("«" + cl.ColumnName + "»") || item.Text.Contains("<" + cl.ColumnName + ">"))
{
item.Text = (string.IsNullOrEmpty(dr[cl.ColumnName].ToString()) ? " " : dr[cl.ColumnName].ToString());
FindSingleAnglebrackets = false;
}
else if (PreItem != null && (PreItem.Text == "<" || PreItem.Text == "«") && (item.Text.Trim() == cl.ColumnName))
{
FindSingleAnglebrackets = true;
PreItem.Text = "";
item.Text = (string.IsNullOrEmpty(dr[cl.ColumnName].ToString()) ? " " : dr[cl.ColumnName].ToString());
}
else if (FindSingleAnglebrackets && (item.Text == "»" || item.Text == ">"))
{
item.Text = "";
FindSingleAnglebrackets = false;
}
}
PreItem = item;
}
}
#endregion

#region replace \v to new Break()
var body = doc.MainDocumentPart.Document.Body;

var paras = body.Elements<Paragraph>();
foreach (var para in paras)
{
foreach (var run in para.Elements<Run>())
{
foreach (var text in run.Elements<Text>())
{
if (text.Text.Contains("MS_Doc_New_Line"))
{
string[] ss = text.Text.Split(new string[] { "MS_Doc_New_Line" }, StringSplitOptions.None);
text.Text = text.Text = "";
int n = 0;
foreach (string s in ss)
{
n++;
run.AppendChild(new Text(s));
if (n != ss.Length)
{
run.AppendChild(new Break());
}
}
}
}
}
}
#endregion

doc.MainDocumentPart.Document.Save();
}
}
public static void MergeDocuments(params string[] filepaths)
{

//filepaths = new[] { "D:\\one.docx", "D:\\two.docx", "D:\\three.docx", "D:\\four.docx", "D:\\five.docx" };
if (filepaths != null && filepaths.Length > 1)

using (WordprocessingDocument myDoc = WordprocessingDocument.Open(@filepaths[0], true))
{
MainDocumentPart mainPart = myDoc.MainDocumentPart;

for (int i = 1; i < filepaths.Length; i++)
{
string altChunkId = "AltChunkId" + i;
AlternativeFormatImportPart chunk = mainPart.AddAlternativeFormatImportPart(
AlternativeFormatImportPartType.WordprocessingML, altChunkId);
using (FileStream fileStream = File.Open(@filepaths[i], FileMode.Open))
{
chunk.FeedData(fileStream);
}
DocumentFormat.OpenXml.Wordprocessing.AltChunk altChunk = new DocumentFormat.OpenXml.Wordprocessing.AltChunk();
altChunk.Id = altChunkId;
//new page, if you like it...
mainPart.Document.Body.AppendChild(new Paragraph(new Run(new Break() { Type = BreakValues.Page })));
//next document
mainPart.Document.Body.InsertAfter(altChunk, mainPart.Document.Body.Elements<Paragraph>().Last());
}
mainPart.Document.Save();
myDoc.Close();
}
}

然后像这样使用它们:

DataTable dt = new DataTable();
dt.Columns.Add("Date");
dt.Columns.Add("Today");
dt.Columns.Add("Addr1");
dt.Columns.Add("Addr2");
dt.Columns.Add("PreferContact");
dt.Columns.Add("TenantName");
//......

DataRow nr = dt.NewRow();
nr["Date"] = DateTime.Now.ToString("dd/MM/yyyy");
nr["Today"] = DateTime.Now.ToString("dd/MM/yyyy");
//......
dt.Rows.Add(nr);


string sourceFile = "c:\my_template.docx"; //this is where you store your template
string filePath = "c:\final.docx"; //this is where your result file locate
Mailmerge(sourceFile, filePath, nr, dt.Columns);

您的模板 (c:\my_template.docx) 就像普通的 .docx 文件一样,您需要在其中指定您的字段:

<field>

因此,您的模板 (c:\my_template.docx) 应该是这样的:

<Today> 

<DebtorName>
<DebtorADDR>
<DebtorEmail>


Dear <Dear>,

Congratulations on yourr property <PlanNo> <BuildAddress>. Your unit number is <LotNo> ...............

此外,如果您的某些字段包含换行符,请使用:

nr["Address"] = my_address_text_contains_line_breaks.Replace(Environment.NewLine, "MS_Doc_New_Line");

关于c# - 你如何在c#中邮件合并一个word文档,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31874300/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com