使用OpenXml和C#复制Word文档

我使用Word和OpenXml在C#ASP.NET Web应用程序中提供邮件合并function:

1)上传文档,其中包含许多预定义的字符串以进行替换。

2)使用OpenXML SDK 2.0我打开Word文档,将mainDocumentPart作为字符串并使用Regex执行替换。

3)然后我使用OpenXML创建一个新文档,添加一个新的mainDocumentPart并将替换产生的字符串插入到这个mainDocumentPart中。

但是,新文档中的所有格式/样式等都将丢失。

我猜我可以单独复制和添加样式,定义,注释部分等来模仿原始文档。

但是有没有一种方法使用Open XML复制文档,允许我在新副本上执行替换?

谢谢。

这段代码应该将现有文档中的所有部分复制到新文档中。

using (var mainDoc = WordprocessingDocument.Open(@"c:\sourcedoc.docx", false)) using (var resultDoc = WordprocessingDocument.Create(@"c:\newdoc.docx", WordprocessingDocumentType.Document)) { // copy parts from source document to new document foreach (var part in mainDoc.Parts) resultDoc.AddPart(part.OpenXmlPart, part.RelationshipId); // perform replacements in resultDoc.MainDocumentPart // ... } 

我第二次使用内容控制建议。 使用它们标记文档中要执行替换的区域是迄今为止最简单的方法。

至于复制文档(并保留整个文档内容,样式和所有内容),它相对容易:

 string documentURL = "full URL to your document"; byte[] docAsArray = File.ReadAllBytes(documentURL); using (MemoryStream stream = new MemoryStream) { stream.Write(docAsArray, 0, docAsArray.Length); // THIS performs doc copy using (WordprocessingDocument doc = WordprocessingDocument.Open(stream, true)) { // perform content control substitution here, making sure to call .Save() // on any documents Part's changed. } File.WriteAllBytes("full URL of your new doc to save, including .docx", stream.ToArray()); } 

实际上使用LINQ找到内容控件是小菜一碟。 以下示例查找所有简单文本内容控件(键入为SdtRun):

 using (WordprocessingDocument doc = WordprocessingDocument.Open(stream, true)) { var mainDocument = doc.MainDocumentPart.Document; var contentControls = from sdt in mainDocument.Descendants() select sdt; foreach (var cc in contentControls) { // drill down through the containment hierarchy to get to // the contained  object cc.SdtContentRun.GetFirstChild().GetFirstChild().Text = "my replacement string"; } } 

元素可能尚不存在,但创建它们很简单:

 cc.SdtContentRun.Append(new Run(new Text("my replacement string"))); 

希望能帮助别人。 :d

我做了一些非常相似的事情,但我没有使用文本替换字符串,而是使用Word Content Controls。 我在以下博客文章SharePoint和Open Xml中记录了一些细节。 该技术并非特定于SharePoint。 您可以在纯ASP.NET或其他应用程序中重用该模式。

此外,我强烈建议您查看Eric White的博客 ,了解有关Open Xml的提示,技巧和技巧。 具体来说,查看Open Xmlpost的内存中操作 ,以及Word内容控制post。 从长远来看,我认为你会发现这些更有帮助。

希望这可以帮助。

作为上述的补遗; 可能更有用的是找到已标记的内容控件(使用GUI一词)。 我最近编写了一些软件,其中填充了包含附加标签的内容控件的文档模板。 要找到它们只是上述LINQ查询的扩展:

 var mainDocument = doc.MainDocumentPart.Document; var taggedContentControls = from sdt in mainDocument.Descendants() let sdtPr = sdt.GetFirstChild() let tag = (sdtPr == null ? null : sdtPr.GetFirstChild()) where (tag != null) select new { SdtElem = sdt, TagName = tag.GetAttribute("val", W).Value }; 

我从其他地方得到了这个代码但是不记得现在在哪里; 完全的功劳归于他们。

该查询只是创建一个匿名类型的IEnumerable,其中包含内容控件及其关联的标记作为属性。 便利!

当您通过将扩展名更改为zip并打开它来查看openxml文档时,您会看到该单词子文件夹包含_rels文件夹,其中列出了所有关系。 这些关系指向你提到的部分(风格……)。 实际上你需要这些部分,因为它们包含格式的定义。 因此,不复制它们将导致新文档使用normal.dot文件中定义的格式,而不是原始文档中定义的格式。 所以我认为你必须复制它们。