Microsoft KB Archive/311461

= How to use ASP.NET or Visual Basic .NET to transform XML to Rich Text Format for Microsoft Word 2002 =

Article ID: 311461

Article Last Modified on 5/13/2007

-

APPLIES TO


 * Microsoft Office Word 2007
 * Microsoft Office Word 2003
 * Microsoft Visual Basic .NET 2002 Standard Edition
 * Microsoft ASP.NET 1.0
 * Microsoft Word 2002 Standard Edition
 * Microsoft .NET Framework Class Libraries 1.0
 * Microsoft Visual Basic .NET 2003 Standard Edition
 * Microsoft ASP.NET 1.1

-



This article was previously published under Q311461



IN THIS TASK

 * SUMMARY
 * The Rich Text Format (RTF) Specification
 * Transform XML to RTF
 * Transform a DataSet Into RTF
 * RTF Troubleshooting Tips
 * REFERENCES



SUMMARY
Use this step-by-step guide to generate Rich Text Format (RTF) from Extensible Markup Language (XML) by using Visual Basic .NET.

Rich Text Format is a text-based format that encodes formatted text, document layout, and graphics. It is commonly used with Microsoft Word. Because RTF is text-based, it can be easily generated with code. If you have XML data that you want to display in Word as a catalog/list or mail merge type document, then transforming your XML data into an RTF stream might be an ideal solution for you. And, in fact, if you are developing a solution where you generate documents on a Web server, then generating those documents using a text-based format, such as HTML or RTF, is preferred over using server-side Automation of Word.

This article provides sample code, with step-by-step instructions, to transform XML into RTF for display in Word by using several approaches:
 * Save the RTF to a file and open it in Word.
 * Transfer the RTF to Word by using the Windows Clipboard.
 * Stream the RTF to Word hosted in Microsoft Internet Explorer from an ASP.NET Web Application.

back to the top

The Rich Text Format Specification
The Rich Text Format (RTF) specification is a public specification to generate RTF-compatible text files. You can use the documentation for the specification at the following Microsoft Developer Network (MSDN) Web site as a resource to help you build your own RTF files. However, the specification is provided &quot;as-is&quot;, and no support is provided by Microsoft Technical Support for the specification. Click the following links for the RTF Specifications:

Rich Text Format Specification, version 1.6

Rich Text Format Specification, version 1.7

back to the top

Transform XML to RTF
You can take valid XML from any source and transform it to RTF. The following procedure illustrates how you can transform custom XML into RTF either saved to a file or copied to the clipboard.  Create a new Visual Basic .NET Windows Application. Form1 is created for you. Add two button controls to Form1. On the View menu, click Code.  Insert the following at the top of the code window before the Form1 Class implementation: Imports System.Xml Imports System.Xml.Xsl Imports System.IO   Add the following code to the Form1 Class implementation (before End Class): Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Button1.Text = &quot;To File&quot; Button2.Text = &quot;To Clipboard&quot;

End Sub

Private Sub ButtonsClick(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles Button1.Click, Button2.Click

Dim sPath As String = Directory.GetParent(Directory.GetCurrentDirectory).ToString

' Open the XML file. Dim xmlDoc As New XmlDocument xmlDoc.Load(sPath & &quot;\Dictionary.xml&quot;)

' Open the XSL file. Dim xslDoc As New XslTransform xslDoc.Load(sPath & &quot;\Dictionary.xslt&quot;)

Select Case sender.name Case &quot;Button1&quot; ' Transform the XSL and save it to file. Dim TWrtr As New XmlTextWriter(sPath & &quot;\Dictionary.RTF&quot;, System.Text.Encoding.Default) xslDoc.Transform(xmlDoc, Nothing, TWrtr, Nothing) TWrtr.Close MsgBox(&quot;Transformed RTF saved to &quot; & sPath & &quot;\Dictionary.RTF&quot;) Case &quot;Button2&quot; ' Transform the XSL and copy it to the clipboard. Dim SWrtr As New StringWriter xslDoc.Transform(xmlDoc, Nothing, SWrtr, Nothing) Dim datObj As New DataObject(DataFormats.Rtf, SWrtr) Clipboard.SetDataObject(datObj) SWrtr.Close MsgBox(&quot;Transformed RTF copied to the clipboard.&quot;) End Select

End Sub  Add an XML file to your project:  On the Project menu, click Add New Item.</li> From the list of templates, click XML File.</li> Type the name Dictionary.xml and then click Open.</li>  Append the following to the contents of Dictionary.xml: <Dictionary> <Entries> <Entry> <Word Type=&quot;1&quot;>Energetic</Word> <Definition>Having, exerting, or displaying energy</Definition> </Entry> <Entry> <Word Type=&quot;1&quot;>Happy</Word> <Definition>Enjoying, displaying, or characterized by pleasure or joy</Definition> </Entry> <Entry> <Word Type=&quot;2&quot;>Emotion</Word> <Definition>A complex, strong subjective response</Definition> </Entry> </Entries> </Dictionary> </li></ol> </li> Add an XSLT file to your project: <ol style="list-style-type: lower-alpha;"> On the Project menu, click Add New Item.</li> From the list of templates, click XSLT File.</li> Type the name Dictionary.xslt and then click Open.</li>  Replace the contents of Dictionary.xslt with the following: <?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?> <xsl:stylesheet version=&quot;1.0&quot; xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;>

<xsl:output method=&quot;text&quot;/> <xsl:template match=&quot;/&quot;>

<xsl:text>{\rtf1</xsl:text>

<xsl:for-each select=&quot;Dictionary/Entries/Entry&quot;>

<xsl:text>\par\b </xsl:text> <xsl:value-of select=&quot;Word&quot;/> <xsl:text>\b0\i </xsl:text> <xsl:if test=&quot;Word[@Type='1']&quot;>adj.</xsl:if> <xsl:if test=&quot;Word[@Type='2']&quot;>n.</xsl:if> <xsl:text>\i0\par </xsl:text> <xsl:value-of select=&quot;Definition&quot;/> <xsl:text>\par</xsl:text> </xsl:for-each>

<xsl:text>}</xsl:text>

</xsl:template> </xsl:stylesheet> </li></ol> </li> Press F5 to build and run the program.</li> Click To File to save the transformed XML to a file (Dictionary.rtf). You can open the RTF file in Word to examine the results of the transformation.</li> Click To Clipboard to copy the transformed XML to the Windows clipboard. You can then paste the clipboard contents into a new or existing Word document to see the results.</li></ol>

back to the top

Transform a DataSet Into RTF
Visual Basic .NET allows to you to easily do transformations on datasets. This procedure shows you how you can take related data from the sample Northwind database and transform it to RTF. Two different transformations are demonstrated: a simple RTF document that lists Customer contact information and a somewhat more complex RTF document that displays order information for customers in a mail merge-type format. <ol> Start a new Visual Basic ASP.NET Web Application and save it to http://localhost/RTFDemo.

WebForm1 is created for you.</li> Add two Button controls to WebForm1.</li> On the View menu, click Code.</li>  Add the following code to the Page_Load function: Button1.Text = &quot;View Contact Information&quot; Button2.Text = &quot;View Customer Orders&quot; </li> <li> Add the following function to the WebForm1 class.

NOTE: The following code assumes you have SQL Server installed on the localhost. If you have to use another computer, change the Data Source member of the connection string accordingly. Private Sub ButtonsClick(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles Button1.Click, Button2.Click

' Connect to the data source. Dim nwindConn As SqlConnection = New SqlConnection( _           &quot;Data Source=localhost;Initial Catalog=Northwind;Integrated Security=SSPI&quot;) nwindConn.Open

' Build a dataset based on whether you requested to view a list of        ' orders or a list of contacts. Dim ds As DataSet Dim sXSL As String Select Case (sender.id)

Case &quot;Button1&quot;

ds = New DataSet(&quot;Contacts&quot;) Dim ContactsDA As SqlDataAdapter = New SqlDataAdapter(&quot;SELECT * FROM Customers&quot;, nwindConn) ContactsDA.Fill(ds, &quot;Customers&quot;) ' XSLT to use for transforming this dataset. sXSL = &quot;Contacts.xslt&quot;

Case &quot;Button2&quot;

ds = New DataSet(&quot;CustomerOrders&quot;)

Dim custDA As SqlDataAdapter = New SqlDataAdapter(&quot;SELECT CustomerID, CompanyName, &quot; & _                   &quot;Address, City, Region, PostalCode, Country FROM Customers&quot;, nwindConn) custDA.Fill(ds, &quot;Customers&quot;)

Dim ordersDA As SqlDataAdapter = New SqlDataAdapter(&quot;SELECT OrderID, CustomerID, Freight &quot; & _                   &quot;FROM Orders&quot;, nwindConn) ordersDA.Fill(ds, &quot;Orders&quot;)

Dim ordersdetailDA As SqlDataAdapter = New SqlDataAdapter( _                   &quot;SELECT [Order Details].OrderID, Products.ProductName, [Order Details].Quantity, &quot; & _                    &quot;[Order Details].[UnitPrice]*[Quantity]*(1-[Discount]) AS ItemTotal &quot; & _                    &quot;FROM Products INNER JOIN [Order Details] ON Products.ProductID = [Order Details].ProductID &quot; _                   , nwindConn)

ordersdetailDA.Fill(ds, &quot;OrderDetails&quot;)

nwindConn.Close

ds.Relations.Add(&quot;CustOrders&quot;, _               ds.Tables(&quot;Customers&quot;).Columns(&quot;CustomerID&quot;), _                ds.Tables(&quot;Orders&quot;).Columns(&quot;CustomerID&quot;)).Nested = True

ds.Relations.Add(&quot;OrdersToOrdersDetail&quot;, _               ds.Tables(&quot;Orders&quot;).Columns(&quot;OrderID&quot;), _                ds.Tables(&quot;OrderDetails&quot;).Columns(&quot;OrderID&quot;)).Nested = True

' XSLT to use for transforming this dataset. sXSL = &quot;CustOrders.xslt&quot;

End Select

' Close the connection to the data source. nwindConn.Close

' Transform the dataset by using the appropriate stylesheet. Dim xmlDoc As XmlDataDocument = New XmlDataDocument(ds) Dim xslTran As XslTransform = New XslTransform xslTran.Load(Server.MapPath(sXSL))

' Stream the results of the transformation to Word. Response.ContentType = &quot;application/msword&quot; Response.Charset = &quot;&quot; Response.ContentEncoding = System.Text.Encoding.Default xslTran.Transform(xmlDoc, Nothing, Response.Output)

End Sub </li> <li> Add the following lines of code at the top of WebForm1.aspx.vb, before the WebForm1 class implementation: Imports System.Data.SqlClient Imports System.Xml Imports System.Xml.Xsl </li> <li>On the Project menu, click Add New Item. From the list of templates, click XSLT File, name the file Contacts.xslt, and then click Open.</li> <li> Replace the contents of Contacts.xslt with the following: <xsl:stylesheet version=&quot;1.0&quot; xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot; xmlns:msxsl=&quot;urn:schemas-microsoft-com:xslt&quot; xmlns:user=&quot;urn:my-scripts&quot; >

<xsl:output method=&quot;text&quot;/>

<xsl:template match=&quot;/&quot;>

<xsl:text>{\rtf1</xsl:text> <xsl:text>{\fonttbl{\f0\froman\fcharset0\fprq2 Times New Roman;}{\f1\fswiss\fcharset0\fprq2 Arial;}}</xsl:text> <xsl:text>{\header\pard\fs50 My Customer Contacts}</xsl:text> <xsl:text>{\footer\pard\fs18 Page {\field{\*\fldinst PAGE}</xsl:text> <xsl:text>{\fldrslt }} of {\field{\*\fldinst NUMPAGES}{\fldrslt 1}} \par}</xsl:text> <xsl:text>\f1\fs20</xsl:text> <xsl:for-each select=&quot;Contacts/Customers&quot;> <xsl:text>\par\b </xsl:text><xsl:value-of select=&quot;CustomerID&quot;/><xsl:text>\b0</xsl:text> <xsl:text>\par </xsl:text><xsl:value-of select=&quot;CompanyName&quot;/> <xsl:text>\par </xsl:text><xsl:value-of select=&quot;ContactName&quot;/> <xsl:text>\par </xsl:text><xsl:value-of select=&quot;Phone&quot;/> <xsl:text>\par</xsl:text> </xsl:for-each> <xsl:text>}</xsl:text>

</xsl:template>

<xsl:template match=&quot;Customers&quot;>

<xsl:text>\par\b </xsl:text><xsl:value-of select=&quot;CustomerID&quot;/><xsl:text>\b0</xsl:text> <xsl:text>\par </xsl:text><xsl:value-of select=&quot;CompanyName&quot;/> <xsl:text>\par </xsl:text><xsl:value-of select=&quot;ContactName&quot;/> <xsl:text>\par </xsl:text><xsl:value-of select=&quot;Phone&quot;/> <xsl:text>\par</xsl:text>

</xsl:template>

</xsl:stylesheet> </li> <li>On the Project menu, click Add New Item. From the list of templates, click XSLT File, name the file CustOrders.xslt, and then click Open.</li> <li> Replace the contents of CustOrders.xslt with the following: <xsl:stylesheet version=&quot;1.0&quot; xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot; xmlns:msxsl=&quot;urn:schemas-microsoft-com:xslt&quot; xmlns:user=&quot;urn:my-scripts&quot; >

<xsl:output method=&quot;text&quot;/>

<msxsl:script language=&quot;VB&quot; implements-prefix=&quot;user&quot;> Dim CustomerTotal as Double = 0 Dim OrderSubtotal as Double = 0 Function AddToOrderSubtotal(amt) amt.MoveNext OrderSubtotal = OrderSubtotal + System.Convert.ToDouble(amt.Current.Value) End Function Function GetOrderSubtotal GetOrderSubtotal = OrderSubtotal End Function Function GetCustomerTotal GetCustomerTotal = CustomerTotal CustomerTotal = 0 End Function Function GetOrderTotal(freight) freight.MoveNext nFreight = System.Convert.ToDouble(freight.Current.Value) GetOrderTotal = nFreight + OrderSubtotal CustomerTotal = nFreight + OrderSubtotal + CustomerTotal OrderSubtotal = 0 End Function </msxsl:script>

<xsl:template match=&quot;CustomerOrders&quot;>

<xsl:text>{\rtf1</xsl:text> <xsl:text>{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255; \red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0; \red255\green255\blue255;\red221\green221\blue221;}</xsl:text> <xsl:text>{\info{\title Sample RTF Document}{\author Microsoft Developer Support}}</xsl:text> <xsl:text>{\header\pard\qc{\fs50 ASP-Generated RTF\par}{\fs18\chdate\par}\par\par}</xsl:text> <xsl:text>{\footer\pard\qc\brdrt\brdrs\brdrw10\brsp100\fs18 Page {\field{\*\fldinst PAGE}</xsl:text> <xsl:text>{\fldrslt }} of {\field{\*\fldinst NUMPAGES}{\fldrslt 1}} \par}</xsl:text> <xsl:apply-templates select=&quot;Customers&quot;/> <xsl:text>}</xsl:text>

</xsl:template>

<xsl:template match=&quot;Customers&quot;>

<xsl:text>\par\pard\fs20\cf2\qr\b </xsl:text><xsl:value-of select=&quot;CustomerID&quot;/><xsl:text>\cf0\b0</xsl:text> <xsl:text>\par\pard </xsl:text><xsl:value-of select=&quot;CompanyName&quot;/> <xsl:text>\par </xsl:text><xsl:value-of select=&quot;Address&quot;/> <xsl:text>\par </xsl:text><xsl:value-of select=&quot;City&quot;/> <xsl:text>, </xsl:text><xsl:value-of select=&quot;Region&quot;/> <xsl:text> </xsl:text><xsl:value-of select=&quot;PostalCode&quot;/> <xsl:text>\par </xsl:text><xsl:value-of select=&quot;Country&quot;/> <xsl:text>\par\par</xsl:text>

<xsl:apply-templates select=&quot;Orders&quot;/>

<xsl:text>\trowd\cellx7000\cellx9000\pard\intbl\ql\b\cbpat1 </xsl:text> <xsl:text>Order Total for the Current Period:\cell </xsl:text> <xsl:text>\qr</xsl:text> <xsl:variable name=&quot;CustTtl&quot; select=&quot;user:GetCustomerTotal&quot;/> <xsl:value-of select=&quot;format-number($CustTtl,'$###0.00')&quot;/> <xsl:text>\cell</xsl:text> <xsl:text>\pard\intbl\row</xsl:text> <xsl:text>\pard\par\pard</xsl:text> <xsl:text>\pard\plain\fs18\cf6\qc</xsl:text> <xsl:choose> <xsl:when test=&quot;$CustTtl = 0&quot;> <xsl:text>\b We've missed hearing from you!\b0 </xsl:text> <xsl:text> At your convenience, please call your personal sales representative </xsl:text> <xsl:text>so that we may discuss our specials for new and returning customers!</xsl:text> </xsl:when> <xsl:when test=&quot;$CustTtl > 2000&quot;> <xsl:text>\b Congratulations!\b0 Your purchases for this period qualify you for a \b 20%\b0 </xsl:text> <xsl:text> discount on one of your next orders. To take advantage of this offer, provide </xsl:text> <xsl:text>the coupon code ABC123XYZ when placing your order.</xsl:text> </xsl:when> <xsl:otherwise> <xsl:text> We value your patronage with Northwind Traders and would love to hear from you. </xsl:text> <xsl:text>If you have any questions about our upcoming line of products or if you want </xsl:text> <xsl:text>a catalog for the coming season, call 1-888-000-000.</xsl:text> </xsl:otherwise> </xsl:choose> <xsl:text>\par\pard</xsl:text> <xsl:text>\par \page</xsl:text>

</xsl:template>

<xsl:template match=&quot;Orders&quot;>

<xsl:text>\trowd\cellx9000\pard\intbl\cbpat9</xsl:text> <xsl:text>\ql\b </xsl:text><xsl:value-of select=&quot;OrderID&quot;/><xsl:text>\b0\cell </xsl:text> <xsl:text>\pard\intbl\row</xsl:text> <xsl:apply-templates select=&quot;OrderDetails&quot;/>

<xsl:text>\trowd\cellx7000\cellx9000\pard\intbl</xsl:text> <xsl:text>\qr Subtotal:\cell </xsl:text> <xsl:value-of select=&quot;format-number(user:GetOrderSubtotal,'$###0.00')&quot;/><xsl:text>\cell</xsl:text> <xsl:text>\pard\intbl\row</xsl:text> <xsl:text>\trowd\cellx7000\cellx9000\pard\intbl</xsl:text> <xsl:text>\qr Freight:\cell </xsl:text> <xsl:value-of select=&quot;format-number(Freight,'$###0.00')&quot;/><xsl:text>\cell</xsl:text> <xsl:text>\pard\intbl\row</xsl:text>

<xsl:text>\trowd\cellx7000\cellx9000\pard\intbl</xsl:text> <xsl:text>\qr Total:\cell </xsl:text> <xsl:value-of select=&quot;format-number(user:GetOrderTotal(Freight), '$###0.00')&quot;/><xsl:text>\cell</xsl:text> <xsl:text>\pard\intbl\row</xsl:text> <xsl:text>\trowd\cellx9000\pard\intbl \cell\pard\intbl\row</xsl:text> </xsl:template>

<xsl:template match=&quot;OrderDetails&quot;>

<xsl:text>\trowd\cellx5000\cellx7000\cellx9000\pard\intbl\ql </xsl:text> <xsl:value-of select=&quot;ProductName&quot;/><xsl:text>\cell </xsl:text> <xsl:text>\qc </xsl:text><xsl:value-of select=&quot;Quantity&quot;/><xsl:text>\cell </xsl:text> <xsl:text>\qr </xsl:text> <xsl:value-of select=&quot;format-number(ItemTotal,'$###0.00')&quot;/><xsl:text>\cell</xsl:text> <xsl:variable name=&quot;RunTotal&quot; select=&quot;user:AddToOrderSubtotal(ItemTotal)&quot;/> <xsl:text>\pard\intbl\row</xsl:text>

</xsl:template>

</xsl:stylesheet> </li> <li>On the Build menu, click Build Solution.</li> <li>Start Internet Explorer and browse to http://localhost/RTFDemo/Webform1.aspx.</li> <li>Click View Contact Information to view the first XML transformation to RTF in Word.</li> <li>Click Back in Internet Explorer.</li> <li>Click View Customer Orders to view the second XML transformation to RTF in Word.</li></ol>

back to the top

RTF Troubleshooting Tips
<ul> <li> As written, the sample code in the Transform a DataSet Into RTF section, streams RTF directly to the browser. Alternatively, you can save the RTF to a file and redirect to the saved file. To do this, replace these lines of code in the sample Response.ContentType = &quot;application/msword&quot; Response.ContentEncoding = System.Text.Encoding.Default Response.Charset = &quot;&quot; xslTran.Transform(xmlDoc, Nothing, Response.Output) with: Dim writer As XmlTextWriter = New XmlTextWriter( _       Server.MapPath(&quot;Results.doc&quot;), System.Text.Encoding.Default) xslTran.Transform(xmlDoc, Nothing, writer) writer.Close Response.Redirect(&quot;Results.doc&quot;) Storing the RTF to a file in this manner allows you to easily examine the structure of the RTF in the file by using any text editor, such as Notepad. Storing the RTF to a file can be a helpful troubleshooting technique if the XSL transformation does not produce the results you expect. </li> <li>When transforming to RTF, be aware of how you present whitespace and carriage returns in your stylesheet because that can affect how Word interprets your RTF. Both code samples in this article use the <xsl:text> element because it forces any white space information in it to be retained.</li> <li>Use <xsl:output method=&quot;text&quot;> in your stylesheet to make sure that your XML is transformed to text (rather than XML, which is the default output method). If you do not specify text as the output method, XML processing instructions may be added to the file. This can prevent Word from correctly interpeting the text as RTF.</li></ul>

back to the top

<div class="references_section">