如何从模板以编程方式创建 Word 文档

发布于 2024-10-04 13:35:32 字数 1179 浏览 5 评论 0原文

我正在尝试在 Microsoft Office Word 中创建大约 600 份报告。这些文档填充了数据库中的数据以及本地驱动器上找到的图像。 我发现,我可以在 Visual Studio 2010 中创建一个 Word 模板项目,并对模板进行编程,以便当您输入单个值(id 号)时,它会自动填充整个文档。

我非常有信心这是可能的。唯一的问题是。如何循环遍历数据库中的所有条目,根据模板打开一个新文档并设置 id 值?

for(int i = 0; i < idnumbers.Count(); i++)
{
     Word.Application app = new Word.Application();
     Word.Document doc = app.Documents.Add(@"C:\..\WordGenerator\bin\Debug\WordTemplate.dotx");
     //input the id-number below: HOW??

     doc.SaveAs(FileName: @"c:\temp\test.docx"); 
}

该应用程序应该只运行一次,生成报告,并且不需要很快。它必须易于开发。

这里的问题是,似乎在 Word 项目之外无法访问 DocumentBase 对象。替代的 Microsoft.Office.Interop.Word.Document 不具有像 SelectContentControlsByTitle 这样允许我查找和设置我的 ContentControls 的功能。这正是我需要做的。


编辑:这就是我的代码现在的样子,将文本插入到我的字段中:

Word.Application app = new Word.Application();

Word.Document doc = app.Documents.Add(@"C:\..\test.dotx");

foreach (Word.ContentControl cc in doc.SelectContentControlsByTitle("MyCCTitle"))
{
    cc.Range.Text += "1234";
}

doc.SaveAs(FileName: @"c:\temp\test.docx");

然后 BeforeSave 上模板上的事件处理程序根据 MyCCTitle 标题对象中的文本填写文档。

I am trying to create about 600 reports in Microsoft office Word. The documents are populated with data from a database, and images found on a local drive.
I have figured out, that I might create a Word Template project in visual studio 2010, and program the template, so that when you enter a single value (id-number), it automatically fills out the entire document.

I am quite confident that this is possible. the only problem is. How do I loop through all entries in the database, open a new document based on the template and set the id-value?

for(int i = 0; i < idnumbers.Count(); i++)
{
     Word.Application app = new Word.Application();
     Word.Document doc = app.Documents.Add(@"C:\..\WordGenerator\bin\Debug\WordTemplate.dotx");
     //input the id-number below: HOW??

     doc.SaveAs(FileName: @"c:\temp\test.docx"); 
}

The application is supposed to run only once, generating the reports, and it doesn´t have to be fast. It just has to be easy to develop.

The problem here is, that it seems that the DocumentBase object is not accessible outside the Word project. The substitute Microsoft.Office.Interop.Word.Document does not have functionality like SelectContentControlsByTitle that allows me to find and set my ContentControls. And that is exactly what I need to do..


EDIT: This is what my code looks like now to insert the text into my field:

Word.Application app = new Word.Application();

Word.Document doc = app.Documents.Add(@"C:\..\test.dotx");

foreach (Word.ContentControl cc in doc.SelectContentControlsByTitle("MyCCTitle"))
{
    cc.Range.Text += "1234";
}

doc.SaveAs(FileName: @"c:\temp\test.docx");

Then an eventhandler on my template on BeforeSave fills out the document based on the text in MyCCTitle-titled object.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

原来分手还会想你 2024-10-11 13:35:32

不要使用办公自动化。
办公自动化在后台打开一个 Office 实例并对其执行操作。打开 Office 实例 600 次似乎并不是一件很有趣的事情。 (而且它永远不会在服务器端运行)

看看 Open XML。您可以在下面找到有关它的负载:

http://openxmldeveloper.org/

编辑:Openxmldeveloper 正在关闭。请在 http://www.ericwhite.com/ 查找上述所有来源。

Don't use Office Automation.
Office automation opens up an instance of office in the background and performs the actions on it. Opening up an office instance 600 times doesn't seem like a very interesting thing to do. (and it would never run serverside)

Take a look at Open XML. You can find loads about it below:

http://openxmldeveloper.org/

edit: Openxmldeveloper is shutting down. Find all the sources mentioned above at http://www.ericwhite.com/ instead.

恬淡成诗 2024-10-11 13:35:32

也许您应该查看 Microsoft.Office.Tools.Word.Document?

Document.SelectContentControlsByTitle

Maybe you should be looking at Microsoft.Office.Tools.Word.Document?

Document.SelectContentControlsByTitle

镜花水月 2024-10-11 13:35:32

这里似乎有两个问题:

  1. 如何启动特定 id 值的流程

  2. 如何填充文档.

sunilp 已回答问题2。数据绑定内容控件是为 Word 2007 及更高版本注入数据的最佳方式。

OP 的焦点似乎是第一季度。

没有命令行开关可以让您将任意值传递到 Word: http://support.microsoft.com /kb/210565

因此,在我看来,您有 4 个选择:

  1. 通过 OpenXML SDK 完成所有工作,根本不打开 Word(正如其他发帖者建议的那样)

  2. 文档(包含您的 ID 号)
  3. 自动化 Word 将 id 号传递到文档,也许作为文档属性

  4. 使用 VSTO 或 Word 宏 (VBA) 在 Word 中创建 600 个文档

Me?我将在 Word 中创建一个包含数据绑定内容控件的 docx,然后保存它。

然后,in 会将我的数据作为自定义 xml 部分注入其中,并保存它。 (您可以使用 OpenXML SDK 执行此步骤,或者如果您需要让 Word 更新您的某些下游流程的绑定,则可以在 Word 中执行此步骤)

Seems that there are 2 questions here:

  1. How do you kick off the process for a particular id-value

  2. How do you populate the document.

sunilp has answered Q2. Data bound content controls are the best way to inject data for Word 2007 and later.

OP's focus looks to be Q1.

There is no command line switch that lets you pass an arbitrary value to Word: http://support.microsoft.com/kb/210565

So as I see it you have 4 choices:

  1. do all the work via the OpenXML SDK, never opening Word at all (as other posters have suggested)

  2. create a minimal pre-existing document (containing your id number) using the OpenXML SDk, then open Word

  3. automate Word to pass the id number to the document, perhaps as a document property

  4. do the work to create the 600 documents in Word using VSTO or Word macros (VBA)

Me? I would create a docx containing data bound content controls in Word, and save it.

Then, in would inject my data into it as a custom xml part, and save it. (This step you could do using the OpenXML SDK, or in Word if you needed to have Word update the bindings for some downstream process of yours)

知你几分 2024-10-11 13:35:32

如果您使用 Word 2007 或 2010 格式,您应该阅读有关 OpenXML 格式的信息

http://msdn.microsoft.com/en-us/library/bb264572(office.12).aspx

You Should read about OpenXML format if you are using Word 2007 or 2010 Format

http://msdn.microsoft.com/en-us/library/bb264572(office.12).aspx

苏别ゝ 2024-10-11 13:35:32

关于上面的答案,我同意 J. Vermeire 的观点,即 OpenXML 是正确的选择。我使用基于 OpenXML 的工具包已经三年多了,它生成由模板和数据库数据合并而成的 .docx 文档。有一个如何使用它的示例这里。该示例展示了如何一次处理一个文档,要处理更多文档,只需添加一个循环并调用一个文档生成方法即可。

In regard to the answers above I agree with J. Vermeire that OpenXML is the way to go. I have been using an OpenXML based toolkit for over three years now, which produces .docx documents, merged from templates and database data. There is an example how to use it here. The example shows how to work with one document at the time, to work with more of them, just add a loop and call a method for document generation.

小兔几 2024-10-11 13:35:32

添加对 Document.OpenXml.dllWindowsBase.dll 的引用

using System.IO.Packaging;

using DocumentFormat.OpenXml.Packaging;

using System.DirectoryServices;

 protected void btnOK_Click(object sender, EventArgs e)
  {

        try
        {
            Package package;
            string strTemplateName = ddl_Templates.SelectedValue.ToString(); //Select Dotx template 
            string strClaimNo = "3284112";
            string strDatePart = DateTime.Now.Year.ToString() + DateTime.Now.Month.ToString() + DateTime.Now.Day.ToString() + DateTime.Now.Hour.ToString() + DateTime.Now.Minute.ToString() + DateTime.Now.Second.ToString() + DateTime.Now.Millisecond.ToString();
            //Word template file
            string templateName = Server.MapPath("~\\LetterTemplates\\" + strTemplateName + ".dotx");
            PackagePart documentPart = null;
            //New file name to be generated from 
            string docFileName = Server.MapPath("~\\LetterTemplates\\" + strClaimNo + "_" + strTemplateName + "_" + strDatePart + ".docx");

            File.Copy(templateName,docFileName, true);
            string fileName = docFileName;
            package = Package.Open(fileName, FileMode.Open, FileAccess.ReadWrite);
            DataSet DS = GetDataSet(strClaimNo, ""); // to get the data from backend to fill in for merge fields
            try
            {
                if (DS != null)
                {
                    if (DS.Tables.Count > 0)
                    {
                        if (DS.Tables[0].Rows.Count > 0)
                        {
                            foreach (System.IO.Packaging.PackageRelationship documentRelationship
                                in package.GetRelationshipsByType(documentRelationshipType))
                            {
                                NameTable nt = new NameTable();
                                nsManager = new XmlNamespaceManager(nt);
                                nsManager.AddNamespace("w",
                                  "http://schemas.openxmlformats.org/wordprocessingml/2006/main");

                                Uri documentUri = PackUriHelper.ResolvePartUri(
                                  new Uri("/", UriKind.Relative), documentRelationship.TargetUri);
                                documentPart = package.GetPart(documentUri);

                                //Get document xml
                                XmlDocument xdoc = new XmlDocument();
                                xdoc.Load(documentPart.GetStream(FileMode.Open, FileAccess.Read));
                                int intMergeFirldCount = xdoc.SelectNodes("//w:t", nsManager).Count;

                                XmlNodeList nodeList = xdoc.SelectNodes("//w:t", nsManager);
                                foreach (XmlNode node in nodeList)
                                {
                                    try
                                    {
                                        xdoc.InnerXml = xdoc.InnerXml.Replace(node.InnerText, DS.Tables[0].Rows[0][node.InnerText.Replace("«", "").Replace("»", "").Trim()].ToString());
                                    }catch(Exception x) { }
                                }

                                StreamWriter streamPart = new StreamWriter(documentPart.GetStream(FileMode.Open, FileAccess.Write));
                                xdoc.Save(streamPart);
                                streamPart.Close();
                                package.Flush();
                                package.Close();
                            }
                            using (WordprocessingDocument template = WordprocessingDocument.Open(docFileName, true))
                            {
                                template.ChangeDocumentType(DocumentFormat.OpenXml.WordprocessingDocumentType.Document);
                                template.MainDocumentPart.Document.Save();
                            }

                            byte[] bytes = System.IO.File.ReadAllBytes(docFileName);
                            System.IO.File.Delete(docFileName);
                            System.Web.HttpResponse response = System.Web.HttpContext.Current.Response;
                            response.ClearContent();
                            response.Clear();
                            response.ContentType = "application/vnd.msword.document.12"; //"application/msword";
                            Response.ContentEncoding = System.Text.Encoding.UTF8;
                            response.AddHeader("Content-Disposition", "attachment; filename=" + strClaimNo + "_" + strTemplateName + "_" + strDatePart + ".docx;");
                            response.BinaryWrite(bytes);
                            response.Flush();
                            response.Close();
                        }
                        else
                        {
                            throw (new Exception("No Records Found."));
                        }
                    }
                    else
                    {
                        throw (new Exception("No Records Found."));
                    }
                }
                else
                {
                    throw (new Exception("No Records Found."));
                }


            }
            catch (Exception ex)
            {
                package.Flush();
                package.Close();
                // Softronic to add code for exception handling
            }
        }
        catch (Exception ex)
        {

            // add code for exception handling
        }
        finally
        {

        }
    }

Add references for Document.OpenXml.dll and WindowsBase.dll

using System.IO.Packaging;

using DocumentFormat.OpenXml.Packaging;

using System.DirectoryServices;

 protected void btnOK_Click(object sender, EventArgs e)
  {

        try
        {
            Package package;
            string strTemplateName = ddl_Templates.SelectedValue.ToString(); //Select Dotx template 
            string strClaimNo = "3284112";
            string strDatePart = DateTime.Now.Year.ToString() + DateTime.Now.Month.ToString() + DateTime.Now.Day.ToString() + DateTime.Now.Hour.ToString() + DateTime.Now.Minute.ToString() + DateTime.Now.Second.ToString() + DateTime.Now.Millisecond.ToString();
            //Word template file
            string templateName = Server.MapPath("~\\LetterTemplates\\" + strTemplateName + ".dotx");
            PackagePart documentPart = null;
            //New file name to be generated from 
            string docFileName = Server.MapPath("~\\LetterTemplates\\" + strClaimNo + "_" + strTemplateName + "_" + strDatePart + ".docx");

            File.Copy(templateName,docFileName, true);
            string fileName = docFileName;
            package = Package.Open(fileName, FileMode.Open, FileAccess.ReadWrite);
            DataSet DS = GetDataSet(strClaimNo, ""); // to get the data from backend to fill in for merge fields
            try
            {
                if (DS != null)
                {
                    if (DS.Tables.Count > 0)
                    {
                        if (DS.Tables[0].Rows.Count > 0)
                        {
                            foreach (System.IO.Packaging.PackageRelationship documentRelationship
                                in package.GetRelationshipsByType(documentRelationshipType))
                            {
                                NameTable nt = new NameTable();
                                nsManager = new XmlNamespaceManager(nt);
                                nsManager.AddNamespace("w",
                                  "http://schemas.openxmlformats.org/wordprocessingml/2006/main");

                                Uri documentUri = PackUriHelper.ResolvePartUri(
                                  new Uri("/", UriKind.Relative), documentRelationship.TargetUri);
                                documentPart = package.GetPart(documentUri);

                                //Get document xml
                                XmlDocument xdoc = new XmlDocument();
                                xdoc.Load(documentPart.GetStream(FileMode.Open, FileAccess.Read));
                                int intMergeFirldCount = xdoc.SelectNodes("//w:t", nsManager).Count;

                                XmlNodeList nodeList = xdoc.SelectNodes("//w:t", nsManager);
                                foreach (XmlNode node in nodeList)
                                {
                                    try
                                    {
                                        xdoc.InnerXml = xdoc.InnerXml.Replace(node.InnerText, DS.Tables[0].Rows[0][node.InnerText.Replace("«", "").Replace("»", "").Trim()].ToString());
                                    }catch(Exception x) { }
                                }

                                StreamWriter streamPart = new StreamWriter(documentPart.GetStream(FileMode.Open, FileAccess.Write));
                                xdoc.Save(streamPart);
                                streamPart.Close();
                                package.Flush();
                                package.Close();
                            }
                            using (WordprocessingDocument template = WordprocessingDocument.Open(docFileName, true))
                            {
                                template.ChangeDocumentType(DocumentFormat.OpenXml.WordprocessingDocumentType.Document);
                                template.MainDocumentPart.Document.Save();
                            }

                            byte[] bytes = System.IO.File.ReadAllBytes(docFileName);
                            System.IO.File.Delete(docFileName);
                            System.Web.HttpResponse response = System.Web.HttpContext.Current.Response;
                            response.ClearContent();
                            response.Clear();
                            response.ContentType = "application/vnd.msword.document.12"; //"application/msword";
                            Response.ContentEncoding = System.Text.Encoding.UTF8;
                            response.AddHeader("Content-Disposition", "attachment; filename=" + strClaimNo + "_" + strTemplateName + "_" + strDatePart + ".docx;");
                            response.BinaryWrite(bytes);
                            response.Flush();
                            response.Close();
                        }
                        else
                        {
                            throw (new Exception("No Records Found."));
                        }
                    }
                    else
                    {
                        throw (new Exception("No Records Found."));
                    }
                }
                else
                {
                    throw (new Exception("No Records Found."));
                }


            }
            catch (Exception ex)
            {
                package.Flush();
                package.Close();
                // Softronic to add code for exception handling
            }
        }
        catch (Exception ex)
        {

            // add code for exception handling
        }
        finally
        {

        }
    }
欲拥i 2024-10-11 13:35:32

如果您使用 Oracle APEX,则为 apexofficeprint.com

如果您使用其他 Web 技术/框架,则为 cloudofficeprint.com

If you use Oracle APEX, then apexofficeprint.com

If you use other web technologies/frameworks, then cloudofficeprint.com

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文