将数据存储中的项目连接到 SQL Server 数据库
使用 Word,可以通过创建数据驱动解决方案来生成文档。 可以创建包含自定义 XML 部件的模板文档,并使用内容控件通过 XML 映射绑定到自定义 XML 数据。 虽然术语 模板 在此上下文中使用,但此文档不是 Word 模板,而是共享 Word 模板文档的某些特征。 然后,可以创建基于 Web 的托管应用程序,以基于模板文档生成新文档。 基于 Web 的托管应用程序打开模板文档,从 Microsoft SQL Server 数据库中检索数据以生成新的自定义 XML 部件,将模板文档的自定义 XML 部件替换为新部件,并将模板文档另存为新的 Word 文档。
本演练说明如何生成新的模板文档,以及如何创建服务器端应用程序,该应用程序生成显示存储在 Microsoft SQL Server 数据库中的数据的文档。 若要生成此应用程序,需要完成以下两个任务:
创建 Word 模板文档。
创建基于 Web 的服务器端应用程序,该应用程序从 Microsoft SQL Server 数据库拉取数据,并根据 Word 模板文档生成新文档。
此示例中使用的编程对象如下所示:
Microsoft Office 系统核心对象模型中的 CustomXMLPart ()
Microsoft Office 系统核心对象模型中的 CustomXMLParts ()
有关内容控件的详细信息,请参阅使用内容控件。
业务方案:创建客户文档生成器
若要创建将数据存储中的项连接到 Microsoft SQL Server 数据库的 Word 文档生成器,请首先生成一个包含映射到 XML 文件的内容控件的模板客户信函生成器文档。 接下来,创建一个基于 Web 的文档生成应用程序,以便选择公司名称来生成自定义文档。 应用程序从 Microsoft SQL Server 数据库中检索客户数据,并使用客户信函生成器生成基于用户选择显示客户数据的新文档。 文档显示以下信息:
- 公司名称
- 联系人姓名
- 联系人标题
- 电话号码
使用以下常规步骤创建 Word 文档生成器。
创建自定义文档生成器并定义每个内容控件的 XML 映射
打开 Word 并创建空白文档。
向文档添加纯文本内容控件以绑定到数据存储中的节点。
内容控件是预定义的内容块。 Word 提供多种类型的内容控件。 这包括文本块、复选框、下拉菜单、组合框、日历控件和图片。 您可以将这些内容控件映射到 XML 文件中的元素。 通过使用 XPath 表达式,可以编程方式将 XML 文件中的内容映射到内容控件。 因此,可以编写简短的应用程序来处理和修改文档中的数据。
若要添加内容控件,请在“ 开发工具 ”选项卡上的“ 控件 ”组中,单击“ 纯文本内容控件”。
向文档添加四个纯文本内容控件。 添加每个控件后,为每个控件分配标题:单击控件;在 “控件 ”组中,单击“ 属性”;在“ 标题 ”框中,键入控件的标题,如以下列表所示:,然后单击“ 确定”。
- 公司名称
- 联系人姓名
- 联系人标题
- 电话号码
还可以使用以下Visual Basic for Applications (VBA) 代码向文档添加内容控件。 按 Alt+F11 打开 Visual Basic 编辑器,将代码粘贴到代码窗口中,单击过程中的任意位置,然后按 F5 运行代码并将四个内容控件添加到模板文档。
Sub AddContentControls() Selection.Range.ContentControls.Add (wdContentControlText) Selection.ParentContentControl.Title = "Company Name" Selection.ParentContentControl.Tag = "Company Name" Selection.MoveDown Unit:=wdLine, Count:=1 Selection.TypeParagraph Selection.Range.ContentControls.Add (wdContentControlText) Selection.ParentContentControl.Title = "Contact Name" Selection.ParentContentControl.Tag = "Contact Name" Selection.MoveDown Unit:=wdLine, Count:=1 Selection.TypeParagraph Selection.Range.ContentControls.Add (wdContentControlText) Selection.ParentContentControl.Title = "Contact Title" Selection.ParentContentControl.Tag = "Contact Title" Selection.MoveDown Unit:=wdLine, Count:=1 Selection.TypeParagraph Selection.Range.ContentControls.Add (wdContentControlText) Selection.ParentContentControl.Title = "Phone Number" Selection.ParentContentControl.Tag = "Phone Number" Selection.MoveDown Unit:=wdLine, Count:=1 Selection.TypeParagraph End Sub
在内容控件上设置 XML 映射。
XML 映射是 Word 的一项功能,可用于在文档和 XML 文件之间创建链接。 这在文档格式和自定义 XML 数据之间实现了真正的数据/视图分隔。
若要加载自定义 XML 部件,必须首先使用 CustomXMLParts 集合的 Add 方法将新的数据存储添加到 Document 对象。 这会向文档追加新的空数据存储。 由于它为空,因此尚不能使用它。 接下来,必须通过调用使用 XML 文件的有效路径作为参数的 CustomXMLPart 对象的 Load 方法,将自定义 XML 部件从 XML 文件加载到数据存储中。
保存文档,将其命名为 CustomerLetterGenerator.docm。
注意
由于它包含 VBA 代码,因此必须将文档另存为启用宏的文档文件 (.docm) .|
以下过程说明如何将内容控件映射到示例自定义 XML 文件。 创建一个有效的自定义 XML 文件,保存该文件,然后使用Visual Basic for Applications (VBA) 代码将包含要映射到的信息的数据存储添加到模板文档。
在内容控件上设置 XML 映射
创建文本文件并将其另存为CustomerData.xml。
将以下 XML 代码复制到文本文件中并保存该文件。
<?xml version="1.0"?> <Customer> <CompanyName>Alfreds Futterkiste</CompanyName> <ContactName>Maria Anders</ContactName> <ContactTitle>Sales Representative</ContactTitle> <Phone>030-0074321</Phone> </Customer>
按 Alt+F11 打开 Visual Basic 编辑器,将以下代码粘贴到代码窗口中,单击过程中的任意位置,然后按 F5 运行代码并将 XML 文件附加到模板文档,使其成为可用的数据存储项。
Public Sub LoadXML() ' Load CustomerData.xml file ActiveDocument.CustomXMLParts.Add ActiveDocument.CustomXMLParts(ActiveDocument.CustomXMLParts.Count).Load ("C:\CustomerData.xml") End Sub
注意
至少有三个默认的自定义 XML 部件始终使用文档创建:“封面”、“文档属性”和“应用属性”。 此外,还可以在给定计算机上创建各种其他自定义 XML 部件,具体取决于多个因素。 其中包括安装的加载项、与 SharePoint 的连接等。 在前面的代码中对 CustomXMLParts 集合调用 Add 方法会添加一个附加的 XML 部件,其中加载了 XML 文件。 在下一行代码中,将在此部分调用 Load 方法。
若要确定要在其中加载 XML 文件的部件的索引号,必须将自定义 XML 部件的计数传递给 Load 方法。
ActiveDocument.CustomXMLParts(ActiveDocument.CustomXMLParts.Count).Load ("C:\CustomerData.xml")
在引用所添加数据存储中的节点的内容控件上设置 XML 映射。
若要创建 XML 映射,请使用 XPath 表达式,该表达式指向要将内容控件映射到的自定义 XML 数据部件中的节点。 将数据存储添加到文档 (并且数据存储指向有效的 XML 文件) 后,即可将其节点之一映射到内容控件。
为此,请使用 XMLMapping 对象的 SetMapping 方法将包含有效 XPath 的 String 传递给 ContentControl 对象, (通过使用 ContentControl 对象的 XMLMapping 属性) 。 打开 Visual Basic 编辑器并运行以下 VBA 代码,将内容控件绑定到数据存储中的项。
Public Sub MapXML() Dim strXPath1 As String strXPath1 = "/Customer/CompanyName" ActiveDocument.ContentControls(1).XMLMapping.SetMapping strXPath1 Dim strXPath2 As String strXPath2 = "/Customer/ContactName" ActiveDocument.ContentControls(2).XMLMapping.SetMapping strXPath2 Dim strXPath3 As String strXPath3 = "/Customer/ContactTitle" ActiveDocument.ContentControls(3).XMLMapping.SetMapping strXPath3 Dim strXPath4 As String strXPath4 = "/Customer/Phone" ActiveDocument.ContentControls(4).XMLMapping.SetMapping strXPath4
创建从SQL Server数据库拉取数据并生成新文档的Server-Side应用程序
可以创建一个基于 Web 的应用程序,使用户能够选择公司名称并生成自定义信函。 基于 Web 的应用程序从SQL Server数据库中检索客户数据,打开客户信函模板文档,并根据用户选择创建显示客户数据的新文档。 此基于 Web 的应用程序不需要使用 Word 或 VBA。 使用常用的托管代码 (Visual Basic .NET 或 C#) 语言生成此应用程序。
注意
此处显示的基于 Web 的应用程序从 Northwind.mdf 数据库获取其数据。 此数据库随以前版本的 SQL Server 和 Office 一起安装。 如果计算机上没有 Northwind 数据库,可以从以下站点下载该数据库: Northwind 数据库
创建从SQL Server数据库拉取数据并生成新文档的服务器端应用程序
打开 Visual Studio 或 Visual Web Developer。
创建 ASP.NET Web 应用程序并将其命名为 SqlServerSample。
在以下步骤中,你将 ASP.NET Web 应用程序连接到SQL Server数据库。
将以下连接字符串添加到 Visual Studio 项目中的 Web.config 文件。
<connectionStrings> <add name="NorthwindConnectionString" connectionString="data source=(local);database=Northwind; integrated security=SSPI;persist security info=false;" providerName="System.Data.SqlClient" /> </connectionStrings>
在 Visual Studio 项目中,将 CustomerLetterGenerator.docm 文档添加到 App_Data 文件夹:右键单击 “App_Data”,指向“ 添加”,单击“ 现有项”,浏览到保存文档的位置,选择该文档,然后单击“ 添加”。
向项目添加对WindowsBase.dll的引用:右键单击“ 引用”,单击“ 添加引用”,单击“ .NET ”选项卡,选择“ WindowsBase”,然后单击“ 确定”。
在 Web.config 文件中配置程序集,如下所示。
<compilation debug="false"> <assemblies> <add assembly="WindowsBase, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> </assemblies> </compilation>
将 Web 窗体添加到项目:在“ 项目 ”菜单上,单击“ 添加新项”;在 “已安装的模板”下,单击“ Web”;选择“ Web 窗体”,然后单击“ 添加”。
在解决方案资源管理器中,右键单击“属性”,然后单击“打开”。
在“ Web ”选项卡上的“ 启动操作”下,选择“ 特定页面”,单击浏览按钮,然后导航到页面 “WebForm1.aspx”。
将以下代码添加到 WebForm1.aspx 文件,覆盖由开始标记和结束
<html>
标记绑定的文件部分。<html xmlns="https://www.w3.org/1999/xhtml"> <head runat="server"> <title>Data-Driven Document Generation - SQL Server Sample</title> </head> <body> <form id="form1" runat="server"> <div> <h1>Customer Letter Generator</h1> <table border="0" cellpadding="0" cellspacing="0" style="width: 100%; height: 12%"> <tr> <td> Choose a customer:</td> <td> <asp:DropDownList ID="ddlCustomer" runat="server" AutoPostBack="True" DataSourceID="CustomerData" DataTextField="CompanyName" DataValueField="CustomerID" Width="301px"> </asp:DropDownList> <asp:SqlDataSource ID="CustomerData" runat="server" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>" SelectCommand="SELECT [CustomerID], [CompanyName] FROM [Customers]" ProviderName="<%$ ConnectionStrings:NorthwindConnectionString.ProviderName %>"> </asp:SqlDataSource> </td> </tr> </table> </div> <br /> <asp:Button ID="Button1" runat="server" OnClick="SubmitBtn_Click" Text="Create Letter" Width="123px" /> </form> </body> </html>
根据所使用的编码语言,将以下 Visual Basic .NET 或 C# 代码添加到项目中相应的 WebForm1.aspx 代码隐藏页。
示例代码:Visual Basic .NET
以下 Visual Basic .NET 示例演示如何绑定到 SQL Server 数据库,以基于客户选择检索数据,以及如何基于 CustomerLetterGenerator.docm 模板文档创建新文档。 将以下代码添加到 WebForm1.aspx.vb 文件,覆盖文件中的现有代码。
Imports System.Collections.Generic
Imports System.Data
Imports System.Data.SqlClient
Imports System.IO
Imports System.IO.Packaging
Imports System.Linq
Imports System.Xml
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Public Class WebForm1
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
End Sub
Private Const strRelRoot As String = "https://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"
Private Sub CreateDocument()
' Get the template document file and create a stream from it
Const DocumentFile As String = "~/App_Data/CustomerLetterGenerator.docm"
' Read the file into memory
Dim buffer() As Byte = File.ReadAllBytes(Server.MapPath(DocumentFile))
Dim memoryStream As MemoryStream = New MemoryStream(buffer, True)
buffer = Nothing
' Open the document in the stream and replace the custom XML part
Dim pkgFile As Package = Package.Open(memoryStream, FileMode.Open, FileAccess.ReadWrite)
Dim pkgrcOfficeDocument As PackageRelationshipCollection = pkgFile.GetRelationshipsByType(strRelRoot)
For Each pkgr As PackageRelationship In pkgrcOfficeDocument
If (pkgr.SourceUri.OriginalString = "/") Then
' Get the root part
Dim pkgpRoot As PackagePart = pkgFile.GetPart(New Uri(("/" + pkgr.TargetUri.ToString), UriKind.Relative))
' Add a custom XML part to the package
Dim uriData As Uri = New Uri("/customXML/item1.xml", UriKind.Relative)
If pkgFile.PartExists(uriData) Then
' Delete part "/customXML/item1.xml" part
pkgFile.DeletePart(uriData)
End If
' Load the custom XML data
Dim pkgprtData As PackagePart = pkgFile.CreatePart(uriData, "application/xml")
GetDataFromSQLServer(pkgprtData.GetStream, ddlCustomer.SelectedValue)
End If
Next
' Close the file
pkgFile.Close()
' Return the result
Response.ClearContent()
Response.ClearHeaders()
Response.AddHeader("content-disposition", "attachment; filename=document.docx")
Response.ContentEncoding = System.Text.Encoding.UTF8
memoryStream.WriteTo(Response.OutputStream)
memoryStream.Close()
Response.End()
End Sub
Private Sub GetDataFromSQLServer(ByVal stream As Stream, ByVal customerID As String)
'Connect to a SQL Server database and get data
Dim source As String = ConfigurationManager.ConnectionStrings("NorthwindConnectionString").ConnectionString
Const SqlStatement As String = "SELECT CompanyName, ContactName, ContactTitle, Phone FROM Customers WHERE CustomerID=@customerID"
Dim conn As SqlConnection = New SqlConnection(source)
conn.Open()
Dim cmd As SqlCommand = New SqlCommand(SqlStatement, conn)
cmd.Parameters.AddWithValue("@customerID", customerID)
Dim dr As SqlDataReader = cmd.ExecuteReader
If dr.Read Then
Dim writer As XmlWriter = XmlWriter.Create(stream)
writer.WriteStartElement("Customer")
writer.WriteElementString("CompanyName", CType(dr("CompanyName"), String))
writer.WriteElementString("ContactName", CType(dr("ContactName"), String))
writer.WriteElementString("ContactTitle", CType(dr("ContactTitle"), String))
writer.WriteElementString("Phone", CType(dr("Phone"), String))
writer.WriteEndElement()
writer.Close()
End If
dr.Close()
conn.Close()
End Sub
Protected Sub SubmitBtn_Click(ByVal sender As Object, ByVal e As EventArgs)
CreateDocument()
End Sub
End Class
示例代码:C#
以下 C# 示例演示如何绑定到 SQL Server 数据库,以基于客户选择检索数据,以及如何基于 CustomerLetterGenerator.docm 模板文档创建新文档。 将以下代码添加到 WebForm1.Aspx.cs 文件,并复制现有代码。
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.IO.Packaging;
using System.Linq;
using System.Xml;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace SQLServerSample
{
public partial class WebForm1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
private const string strRelRoot = "https://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
private void CreateDocument()
{
// Get the template document file and create a stream from it
const string DocumentFile = @"~/App_Data/CustomerLetterGenerator.docm";
// Read the file into memory
byte[] buffer = File.ReadAllBytes(Server.MapPath(DocumentFile));
MemoryStream memoryStream = new MemoryStream(buffer, true);
buffer = null;
// Open the document in the stream and replace the custom XML part
Package pkgFile = Package.Open(memoryStream, FileMode.Open, FileAccess.ReadWrite);
PackageRelationshipCollection pkgrcOfficeDocument = pkgFile.GetRelationshipsByType(strRelRoot);
foreach (PackageRelationship pkgr in pkgrcOfficeDocument)
{
if (pkgr.SourceUri.OriginalString == "/")
{
// Get the root part
PackagePart pkgpRoot = pkgFile.GetPart(new Uri("/" + pkgr.TargetUri.ToString(), UriKind.Relative));
// Add a custom XML part to the package
Uri uriData = new Uri("/customXML/item1.xml", UriKind.Relative);
if (pkgFile.PartExists(uriData))
{
// Delete document "/customXML/item1.xml" part
pkgFile.DeletePart(uriData);
}
// Load the custom XML data
PackagePart pkgprtData = pkgFile.CreatePart(uriData, "application/xml");
GetDataFromSQLServer(pkgprtData.GetStream(), ddlCustomer.SelectedValue);
}
}
// Close the file
pkgFile.Close();
// Return the result
Response.ClearContent();
Response.ClearHeaders();
Response.AddHeader("content-disposition", "attachment; filename=CustomLetter.docx");
Response.ContentEncoding = System.Text.Encoding.UTF8;
memoryStream.WriteTo(Response.OutputStream);
memoryStream.Close();
Response.End();
}
private void GetDataFromSQLServer(Stream stream, string customerID)
{
// Connect to a SQL Server database and get data
String source = System.Configuration.ConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString;
const string SqlStatement =
"SELECT CompanyName, ContactName, ContactTitle, Phone FROM Customers WHERE CustomerID=@customerID";
using (SqlConnection conn = new SqlConnection(source))
{
conn.Open();
SqlCommand cmd = new SqlCommand(SqlStatement, conn);
cmd.Parameters.AddWithValue("@customerID", customerID);
SqlDataReader dr = cmd.ExecuteReader();
if (dr.Read())
{
XmlWriter writer = XmlWriter.Create(stream);
writer.WriteStartElement("Customer");
writer.WriteElementString("CompanyName", (string)dr["CompanyName"]);
writer.WriteElementString("ContactName", (string)dr["ContactName"]);
writer.WriteElementString("ContactTitle", (string)dr["ContactTitle"]);
writer.WriteElementString("Phone", (string)dr["Phone"]);
writer.WriteEndElement();
writer.Close();
}
dr.Close();
conn.Close();
}
}
protected void SubmitBtn_Click(object sender, EventArgs e)
{
CreateDocument();
}
}
}
有关使用 ASP.NET 2.0 的详细信息,请参阅 https://www.asp.net/get-started/。
本文介绍如何从SQL Server数据库提取数据并将其插入模板文档中。 还可以从其他数据源中提取数据,例如 Access 和 Excel。 有关如何以编程方式连接到这些应用程序中的数据的详细信息,请参阅 Access 和 Excel 开发人员文档。
支持和反馈
有关于 Office VBA 或本文档的疑问或反馈? 请参阅 Office VBA 支持和反馈,获取有关如何接收支持和提供反馈的指南。