【问题标题】:Generate multi-page document in Open XML from List of data从数据列表生成 Open XML 中的多页文档
【发布时间】:2016-05-27 15:46:59
【问题描述】:

对于我正在进行的一个项目,我正在研究我们的团队通常不使用这些方法来生成文档。通常,我们使用 ActiveReports 生成提供给客户的 PDF,但由于我们的纸张大小,这不是一个选项 - 我们在获取任何不是 8.5" x 11 的文件时遇到了严重问题" 与浏览器端 PDF 插件或我们支持的打印机完美搭配。

我正在尝试做的具体事情是使用 1...n 4"x6" 索引卡创建一个文档。如前所述,我需要生成的数据条目数量可变。

我过去使用 Open XML 的唯一方法是获取一个模板,将关键字替换为我想要注入的数据,然后将生成的文档提供给客户端,如下所示:

报告类:

public class ThingReport : IDisposable
{
    #region Variables / Properties

    private readonly string _templatePath = string.Empty;
    private MemoryStream _reportStream;

    #endregion Variables / Properties

    #region Constructor

    public ThingReport(string templatePath)
    {
        _templatePath = templatePath;
    }

    #endregion Constructor

    #region Methods

    public void Dispose()
    {
        _reportStream.Dispose();
    }

    public void RunReport(IList<Thing> things)
    {
        _reportStream = new MemoryStream();

        using (FileStream fs = File.OpenRead(_templatePath))
        {
            fs.CopyTo(_reportStream);
            _reportStream.Seek(0x00000000, SeekOrigin.Begin);
            fs.Close();
        }

        using (WordprocessingDocument pkgDoc = WordprocessingDocument.Open(_reportStream, true))
        {
            // Set basic properties of the document...
            pkgDoc.PackageProperties.Creator = "My App";
            pkgDoc.PackageProperties.Created = DateTime.Now;
            pkgDoc.PackageProperties.Title = "Some document";
            pkgDoc.PackageProperties.ContentType = "application/msword";

            // Read the full document text, in prep for editing...
            string docText;
            using (StreamReader sr = new StreamReader(pkgDoc.MainDocumentPart.GetStream()))
            {
                docText = sr.ReadToEnd();
                sr.Close();
            }

            // Replace the recipient.
            // Source: https://msdn.microsoft.com/en-us/library/office/bb508261.aspx
            Regex recipientRegex = new Regex("«Recipient»");
            docText = recipientRegex.Replace(docText, things[0].PersonName);

            // Template has 3 fields in it; replace those fields with details of child data.
            for (int i = 0; i < 3; i++)
            {
                string presentedDate = string.Empty;
                string presentedNotes = string.Empty;
                if (i <= things.Count - 1)
                {
                    var thing = things[i];
                    presentedDate = thing.thingDate.ToString("MM/dd/yyyy");
                    presentedNotes = thing.Notes;
                }

                string dateReplaceText = string.Format("«ThingDate{0}»", i + 1);
                Regex dateRegex = new Regex(dateReplaceText);
                docText = dateRegex.Replace(docText, presentedDate);

                string noteReplaceText = string.Format("«ThingNote{0}»", i + 1);
                Regex noteRegex = new Regex(noteReplaceText);
                docText = noteRegex.Replace(docText, presentedNotes);
            }

            // Write the modified document to the stream.
            using (StreamWriter sw = new StreamWriter(pkgDoc.MainDocumentPart.GetStream(FileMode.Create)))
            {
                sw.Write(docText);
                sw.Close();
            }

            // Close the unmanaged resource!
            pkgDoc.Close();
        }
    }

    public byte[] Export()
    {
        return _reportStream.ToArray();
    }

    #endregion Methods
}    

我什至从未尝试过同时跨多个数据条目使用 Word 模板。由于这是我团队其他成员都拥有相同经验的技术,我不能问他们如何做到这一点,因为他们和我一样清楚。

我确实查找了Open XML API for word documents,以及一些其他必要的 Google 搜索,了解如何让 Open XML API 执行此操作……但我没有找到任何可以理解的内容。

问题:我可以通过什么方式获取具有可变数量成员的List&lt;Thing&gt;,并使用 Open XML 获取 MS Word 模板以生成页数相等的文档到成员的数量,都使用完全相同的格式?

【问题讨论】:

  • 实际上,您首先应该熟悉如何在 Word UI 中获得最佳结果。我的意思是分析如何使用 Word 的内置功能来实现这一点 - 因为这也是您在 Open XML 中使用的(或自动化 - 没有区别)。例如,这应该是表格格式还是大纲格式?什么应该确定分页方式 - Word 具有格式设置,您可以将其集成到样式中以获得“流畅的流程”。还需要什么其他格式?
  • 一旦你有了一个有用的格式,创建一个包含所有元素(包括样式)的最小文档。保存该文档并在 Open XML SDK Productivity Tool 中打开它。这将向您展示构成文档的基础 Word Open XML 以及生成它的 Open XML SDK 代码(如果您想使用该工具)。这应该给你一个起点。一旦你看到底层的 XML,它可能会告诉你如何“转换”你的列表数据......
  • 我认为您并没有真正阅读我的问题。虽然我确实下载了该工具并在其中打开了我的模板文档,但我看到了一堆乱码,并且没有任何明确的方法可以获取我的单个页面,根据需要多次复制该页面,并替换这些页面上的占位符文本与我的对象的详细信息。 也许对于我正在尝试做的事情来说,Open XML 不是正确的技术——我对此知之甚少——但我想知道我正在做的要么是可能或不可能。
  • 是的,有可能。

标签: c# ms-word export openxml


【解决方案1】:

我建议您创建一个包含多个合并字段的 word 模板以映射到您的事物/对象的成员,然后执行邮件与列表的合并。

使用 Syncfusion 的DocIO 库,您可以更轻松地实现它。 DocIO 是一个 .NET 库,用于读取和写入 Word 2003/2007/2010/2013/2016 文件。如果您符合条件,可通过community license program 免费获得整套控件(也可用于商业应用)。社区许可证是没有限制或水印的完整产品。

例如,让我们创建一个如下所示的带有合并字段的 Word 文档模板,并假设您有一个客户(列表)详细信息列表。

第 1 步:创建控制台应用程序
第 2 步:添加对 Syncfusion.DocIO.Base、Syncfusion.Compression.Base 和 Syncfusion.OfficeChart.Base 的引用
您也可以使用 NuGet 将这些引用添加到您的项目中。
第 3 步:复制并粘贴以下代码 sn-p。确保正确引用输入词模板。

此代码将根据您的要求生成文档,对于每个事物/客户,它将在生成的 Word 文档中生成一个单独的页面。

Download Demo

using System.Collections.Generic;
using Syncfusion.DocIO.DLS;
using Syncfusion.DocIO;

namespace DocIO_MailMerge
{
   class Program
   {
    static void Main(string[] args)
    {
        List<Customer> customers = new List<Customer>();
        customers.Add(new Customer("Maria", "Anders", "maria.Anders@example.com", "USA"));
        customers.Add(new Customer("Ana", "Trujillo", "ana.trujillp@example.com", "USA"));
        customers.Add(new Customer("Antonio", "Moreno", "antonio.moreno@example.com", "UK"));
        customers.Add(new Customer("Thomas", "Hardy", "thomas.hardy@example.com", "Mexico"));

        using (WordDocument wordDocument = new WordDocument(@"Template.docx"))
        {
            wordDocument.MailMerge.Execute(customers);
            wordDocument.Save("Result.docx", FormatType.Docx);
        }

        System.Diagnostics.Process.Start("Result.docx");
    }
}
class Customer
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string MailID { get; set; }
    public string Country { get; set; }
    public Customer(string firstName, string lastName, string emailID, string country)
    {
        FirstName = firstName;
        LastName = lastName;
        MailID = emailID;
        Country = country;
    }
}
}

注意:我为 Syncfusion 工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-10
    • 1970-01-01
    • 2010-12-21
    • 1970-01-01
    • 2011-02-14
    • 1970-01-01
    • 2011-01-25
    • 1970-01-01
    相关资源
    最近更新 更多