Walkthrough: Connect an Item in the Data Store to a Web Service
Word Developer Reference |
Microsoft Office Word 2007 enables you to build data-driven, document-generation solutions. You can create a document template that includes a custom XML part and use content controls to bind to custom XML data by using XML mapping. Then you can create a managed application to build a new document based on the template. The managed application opens the document template, retrieves data from a Web service to build a new custom XML part, replaces the template's custom XML part, and saves as a new document.
This walkthrough explains how to build a new template and how to create a server-side application that generates documents that display data from a Web service. To build this application, you will do the following:
- Create a Word 2007 document template.
- Create a server-side application that pulls data from a Web service and generates new documents based on the Word 2007 document template.
The objects used in this sample are:
- ContentControl
- ContentControls
- CustomXMLPart (Microsoft Office system core object model)
- CustomXMLParts (Microsoft Office system core object model)
- XMLMapping
For more information about content controls, see Working with Content Controls.
Business Scenario: Stock Report
To demonstrate how to build a Word 2007 template and connect an item in the data store to a Web service, you first build a stock report document template with content controls that map to an XML file. Next, you create a document-generation application that enables you to select a stock quote symbol to generate a custom letter. The application retrieves customer data from a Web service and uses the stock report document template to build a new document that displays recent stock data based on a user selection. The document displays the following information:
- Quote Symbol
- Last
- LastTime
- High
- Low
Create a Word Template and Define the XML Mappings for Each Content Control
Use the following steps to create a Word 2007 template:
Open Word 2007.
Create a document.
Create content controls to bind to a node in the data store.
Set the XML mapping on the content control.
XML mapping is a feature of Word 2007 that enables you to create a link between a document and an XML file. This creates true data/view separation between the document formatting and the custom XML data.
To load a custom XML part, you must first add a new data store to a Document object by using the Add method of the CustomXMLParts collection. This appends a new, empty data store to the document. Because it is empty, you cannot use it yet. Next, you must load a custom XML part from an XML file into the data store, by calling the Load method of the CustomXMLPart object, using a valid path to an XML file as the parameter.
Add five plain-text content controls in the following order:
- Content control for Quote Symbol
- Content control for Last
- Content control for Last Time
- Content control for High
- Content control for Low
Save the template document as C:\StockTemplate.docx.
To Set an XML Mapping on a Content Control
The data store in a document in the Word 2007 object model is contained in the CustomXMLParts property of the Document object. The CustomXMLParts property returns a CustomXMLParts collection that contains CustomXMLPart objects. It points to all the data store items that are available to a document. A CustomXMLPart object represents a single custom XML part in the data store.
Note |
---|
In this procedure, you map the content control to a sample custom XML file. |
Create a text file and save it as C:\StockData.xml.
Copy the following XML into the text file and save it.
<?xml version="1.0" encoding="utf-8" ?> <StockData xmlns:dt="urn:schemas-microsoft-com:datatypes"> <Quotes> <Quote Symbol="MSFT"> <Last dt:dt="float">23.87</Last> <LastTime dt:dt="string">1:00 PM</LastTime> <LastSize dt:dt="float">343.00</LastSize> <Ask dt:dt="float">23.86</Ask> <Bid dt:dt="float">23.83</Bid> <Open dt:dt="float">24.08</Open> <Close dt:dt="float">22.85</Close> <High dt:dt="float">24.15</High> <Low dt:dt="float">23.00</Low> <Volume dt:dt="float">175,483,770</Volume> <Change dt:dt="float">1.02</Change> <PercentChange dt:dt="float">4.46</PercentChange> <EPS dt:dt="float">1.26</EPS> <PE dt:dt="float">18.94</PE> <SharesOut dt:dt="float">343.00</SharesOut> <Currency dt:dt="string">USD</Currency> <Exchange dt:dt="string">NASDAQ</Exchange> <Type dt:dt="string">Equity</Type> <CompanyName dt:dt="string"><![CDATA[Microsoft Corporation]]></CompanyName> </Quote> </Quotes> <Attributions> <Timing><![CDATA[Quotes delayed at least 20 min]]></Timing> <Attribution priority="1"><![CDATA[<a href="http://www.comstock-interactivedata.com"><img border="0" align="absmiddle" src="http://office.microsoft.com/Research/Images/splgo.gif" /></a> Quotes supplied by <a href="http://www.comstock-interactivedata.com">Standard & Poor's ComStock, Inc.</a>]]></Attribution> <Attribution priority="1"><![CDATA[<a href="http://moneycentral.msn.com/investor/partsub/funds/mstar.asp"><img border="0" align="absmiddle" src="http://office.microsoft.com/Research/Images/mornlgo.gif" /></a> Fund data provided by <a href="http://moneycentral.msn.com/investor/partsub/funds/mstar.asp">Morningstar, Inc.</a>]]></Attribution> <Attribution priority="2"><![CDATA[<a href="http://privacy.msn.com/tou">Terms of Use</a>]]></Attribution> </Attributions> <Warning>NoWarning</Warning> </StockData>
Open the Microsoft Visual Basic editor and run the following Microsoft Visual Basic for Applications (VBA) code to add a data store to your template document. This sample code demonstrates how to attach an XML file to a document, so that it becomes an available data store item.
' Load StockData.xml file ActiveDocument.CustomXMLParts.Add ActiveDocument.CustomXMLParts(4).Load ("c:\StockData.xml")
Set an XML mapping on a content control that refers to a node in the added data store. To create an XML mapping, you use an XPath expression to the node in the custom XML data part to which you want to map a content control. After you add a data store to your document (and the data store points to a valid XML file), you are ready to map one of its nodes to a content control. To do this, pass a String containing a valid XPath to a ContentControl object by using the SetMapping method of the XMLMapping object (via the XMLMapping property of the ContentControl object). Open the Visual Basic editor and run the following VBA code to bind content controls to items in the data store.
-
Dim strXPath1 As String
strXPath1 = "/Quotes/Quote[@Symbol]" ActiveDocument.ContentControls(1).XMLMapping.SetMapping strXPath1
Dim strXPath2 As String strXPath2 = "/Quotes/Last" ActiveDocument.ContentControls(2).XMLMapping.SetMapping strXPath2
Dim strXPath3 As String strXPath3 = "/Quotes/LastTime" ActiveDocument.ContentControls(3).XMLMapping.SetMapping strXPath3
Dim strXPath4 As String strXPath4 = "/Quotes/High" ActiveDocument.ContentControls(4).XMLMapping.SetMapping strXPath4
Dim strXPath5 As String strXPath5 = "/Quotes/Low" ActiveDocument.ContentControls(5).XMLMapping.SetMapping strXPath5
Create a Server-Side Application That Pulls Data from a SQL Server Database and Generates the New Document
You can create a Web-based application that enables users to select a stock quote symbol and generate a custom stock report letter. The Web-based application retrieves stock information through a Web service, opens the stock report document template, and creates a new document that displays stock information based on a user selection. This application does not require the use of Word 2007 or VBA. You can use your favorite managed code (Microsoft Visual Basic .NET or C#) language to build this application.
To create an ASP.NET 2.0 data-driven, document-generation application, do the following:
- Open Microsoft Visual Studio 2005 or Microsoft Visual Web Developer 2005.
- Create a new ASP.NET Web site and name it WebServiceSample.
- Add the StockTemplate.docx to the App_Data folder.
- Add a Web Reference to the http://office.microsoft.com/Research/Providers/MoneyCentral.asmx?WSDL Web service and name it MoneyCentralService.
- Download and install the Microsoft .NET Framework 3.0 (formerly Microsoft WinFX).
- Configure the assembly in the Web.config file as follows:
<compilation debug="false"> <assemblies> <add assembly="WindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> </assemblies> </compilation>
Sample Code
Microsoft Visual Basic .NET
The following sample demonstrates how to connect to a Web Service to retrieve data based on a customer selection and create a new document based on the StockTemplate.docx.
<%@ Page Language="VB" AutoEventWireup="true" %> <%@ Import Namespace="MoneyCentralService" %> <%@ Import Namespace="System.IO" %> <%@ Import Namespace="System.IO.Packaging" %> <%@ Import Namespace="System.Text" %> <%@ Import Namespace="System.Xml" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head id="Head1" runat="server"> <title>Data-Driven Document Generation - Web Service Sample</title> </head>
<script runat='server'>
Private Shared strRelRoot As String = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Protected Sub btnCreateReport_Click(ByVal sender As Object, ByVal e As EventArgs) CreateStockReport() End Sub Private Sub CreateStockReport() ' Get the template file they uploaded and create a stream from it Dim rnd As Random = New Random Dim strRandom As String = rnd.Next.ToString Dim strFileName As String = Server.MapPath((strRandom + ".docx")) Dim stmwrite As Stream = File.Create(strFileName) Dim strTemplateFileName As String = Server.MapPath("~/App_Data/StockTemplate.docx") Dim stmTemplate As Stream = New FileStream(strTemplateFileName, FileMode.Open) Dim brTemplate As BinaryReader = New BinaryReader(stmTemplate) Dim bwDocument As BinaryWriter = New BinaryWriter(stmwrite) bwDocument.Write(brTemplate.ReadBytes(CType(stmTemplate.Length, Integer))) bwDocument.Flush() bwDocument.Close() brTemplate.Close() stmwrite.Close() ' Open the new file Dim pkgFile As Package = Package.Open(strFileName, FileMode.Open, FileAccess.ReadWrite) Dim pkgrcOfficeDocument As PackageRelationshipCollection = pkgFile.GetRelationshipsByType(strRelRoot) Dim pkgpRoot As PackagePart = Nothing For Each pkgr As PackageRelationship In pkgrcOfficeDocument If (pkgr.SourceUri = New Uri("/", UriKind.Relative)) Then 'Get the root part pkgpRoot = 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 template "/customXML/item1.xml" part pkgFile.DeletePart(uriData) End If ' Get stock data Dim mcr As MoneyCentralService.MoneyCentralRemote = New MoneyCentralRemote Dim xdoc As XmlDocument = New XmlDocument xdoc.LoadXml(mcr.DDSQuery(tbSymbol.Text, "", "")) ' Load the part Dim pkgprtData As PackagePart = pkgFile.CreatePart(uriData, "application/xml") xdoc.Save(pkgprtData.GetStream) 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 Response.TransmitFile(strFileName) Response.Flush() Response.Close() Response.End() ' Clean up File.Delete(strFileName) End Sub
</script>
<body> <form id="form1" runat="server"> <div> <h1> Stock Report Generator</h1> Symbol: <asp:TextBox ID="tbSymbol" runat="server"></asp:TextBox> <asp:Button ID="btnCreateReport" runat="server" Text="Create Stock Report" OnClick="btnCreateReport_Click" /> </div> </form> </body> </html>
C#
The following sample demonstrates how to connect to a Web Service to retrieve data based on a customer selection and create a new document based on the StockTemplate.docx.
<%@ Page Language="C#" AutoEventWireup="true"%> <%@ Import Namespace="MoneyCentralService" %> <%@ Import Namespace="System.IO" %> <%@ Import Namespace="System.IO.Packaging" %> <%@ Import Namespace="System.Text" %> <%@ Import Namespace="System.Xml" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head id="Head1" runat="server"> <title>Data-Driven Document Generation - Web Service Sample</title> </head> <script language="C#" runat="server"> static string strRelRoot = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
protected void btnCreateReport_Click(object sender, EventArgs e) { CreateStockReport(); } private void CreateStockReport() { // Get the template file they uploaded and create a stream from it Random rnd = new Random(); String strRandom = rnd.Next().ToString(); String strFileName = Server.MapPath(strRandom + ".docx"); Stream stmwrite = File.Create(strFileName); String strTemplateFileName = Server.MapPath(@"~/App_Data/StockTemplate.docx"); Stream stmTemplate = new FileStream(strTemplateFileName, FileMode.Open); BinaryReader brTemplate = new BinaryReader(stmTemplate); BinaryWriter bwDocument = new BinaryWriter(stmwrite); bwDocument.Write(brTemplate.ReadBytes((int)stmTemplate.Length)); bwDocument.Flush(); bwDocument.Close(); brTemplate.Close(); stmwrite.Close(); // Open the new file Package pkgFile = Package.Open(strFileName, FileMode.Open, FileAccess.ReadWrite); PackageRelationshipCollection pkgrcOfficeDocument = pkgFile.GetRelationshipsByType(strRelRoot); PackagePart pkgpRoot = null; foreach (PackageRelationship pkgr in pkgrcOfficeDocument) { if (pkgr.SourceUri == new Uri("/", UriKind.Relative)) { //Get the root part 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 template "/customXML/item1.xml" part pkgFile.DeletePart(uriData); } // Get stock data MoneyCentralService.MoneyCentralRemote mcr = new MoneyCentralRemote(); XmlDocument xdoc = new XmlDocument(); xdoc.LoadXml(mcr.DDSQuery(tbSymbol.Text, "", "")); // Load the part PackagePart pkgprtData = pkgFile.CreatePart(uriData, "application/xml"); xdoc.Save(pkgprtData.GetStream()); } } // 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; Response.TransmitFile(strFileName); Response.Flush(); Response.Close(); Response.End(); // Clean up File.Delete(strFileName); } </script>
<body> <form id="form1" runat="server"> <div> <h1>Stock Report Generator</h1> Symbol: <asp:TextBox ID="tbSymbol" runat="server"></asp:TextBox> <asp:Button ID="btnCreateReport" runat="server" Text="Create Stock Report" OnClick="btnCreateReport_Click" /> </div> </form> </body> </html>
For more information about working with ASP.NET 2.0, read the ASP.NET QuickStart Tutorials.