Author: Sanjay Kumar Madhva of Sonata Software Limited
Introduction
We may have scenario where we may have to create a word document at places where we have no word installed or running. We can programmatically create a word document using the OpenXML format.
The idea of this article is to show how easy it is to create an OpenXML WordprocessingML using ASP.NET and using System.IO.Packaging provided by WinFx.
What we need, is to create an ASP.NET application that lets user enter multi line of text. The user is provided a button that on click creates a WordprocessingML. When the user clicks on the button all we need to code for, breaking the user entered text into paragraphs and creating an document.xml as shown below. Package it into an OpenXML document.
Content of document.xml
<?xml version="1.0" encoding="utf-8" ?>
<?xml:namespace prefix = w /><w:wordDocument
xmlns:w="http://schemas.microsoft.com/office/word/2005/10/wordml">
<w:body>
<w:p>
<w:r>
<w:t>Text which as paragraph 1 </w:t>
</w:r>
</w:p>
<w:p>
<w:r>
<w:t>Text which as paragraph 2 </w:t>
</w:r>
</w:p>
.
.
.
.
.
.
<w:p>
<w:r>
<w:t>Text which as paragraph n </w:t>
</w:r>
</w:p>
</w:body>
</w:wordDocument>
|
Here are the steps to follow for this project ...
Create a new Web Site
To create an ASP.NET Web site, open visual studio, from the file menu select new web site sub menu.
From the template selection select ASP.NET Web site. and language as Visual Basic.
Add reference to WindowsBase provided WinFx
Right click on the reference and from the pop up menu select “Add Reference” ...
Add reference windows pops up. Select “Windows Base” from the .NET tab as shown in the fig below.
Add a Text box to the web page
Drag and drop TextBox from the ToolBox on to the web page.
Resize the textbox
Resize the textbox to fit to the screen.
Change the property to accept Multi-Line
Change the textbox property to accept multi-line data entry.
... and rename it to mleTextBox1 ...
Add a Button
Rename the Button
Rename the button to GenerateDocument and change the text to “&Generate Document” ...
Add Imports directive
Double-click on the Generate button to go the code behind, then add this code:
Imports System.Xml; Imports System.IO; Imports System.IO.Packaging; |
Create a private method “CreateFile”
Create a method CreateFile which will accept a filepath with file name and content to be written into the document.
The document creation can be achieved by following 5 easy steps:
1. Take the text entered by the user in the multilane edit has to be split into paragraph and creating a “document.xml” as shown under “Content of document.xml”.
2. Creating an instance of Package class.
3. Create the main document part (document.xml) using the package class.
4. Create the relationship file.
5. Close the document.
Private Sub CreateFile(ByVal filepath As String, ByVal content As String)
Dim doc As XmlDocument
doc = New XmlDocument()
Dim _wWordDocument As XmlElement
_wWordDocument = doc.CreateElement("w:wordDocument", _
"http://schemas.microsoft.com/office/word/2005/10/wordml")
doc.AppendChild(_wWordDocument)
Dim _wbody As XmlElement
_wbody = doc.CreateElement("w:body", _
"http://schemas.microsoft.com/office/word/2005/10/wordml")
_wWordDocument.AppendChild(_wbody)
' Check if the string contains a line feed
Dim _SplitStr() As String
_SplitStr = content.Split(vbLf)
' if it contains line feed then each entry with a
' line feed goes to a new paragraph.
Dim row As Integer
For row = 0 To _SplitStr.Length - 1
Dim _wp1 As XmlElement
_wp1 = doc.CreateElement("w:p", _
"http://schemas.microsoft.com/office/word/2005/10/wordml")
_wbody.AppendChild(_wp1)
Dim _wr1 As XmlElement
_wr1 = doc.CreateElement("w:r", _
"http://schemas.microsoft.com/office/word/2005/10/wordml")
_wp1.AppendChild(_wr1)
Dim _wt11 As XmlElement
_wt11 = doc.CreateElement("w:t", _
"http://schemas.microsoft.com/office/word/2005/10/wordml")
_wr1.AppendChild(_wt11)
Dim _wt1 As XmlNode
_wt1 = doc.CreateNode(XmlNodeType.Text, "w:t", _
"http://schemas.microsoft.com/office/word/2005/10/wordml")
_wt1.Value = _SplitStr(row)
_wt11.AppendChild(_wt1)
Next
'-- Step 1 - Creating the Package
Dim _package As Package
_package = Package.Open(filepath, FileMode.Create, FileAccess.ReadWrite)
'-- Step 2 - Create the main document part (document.xml)
Dim _uri As Uri
_uri = New Uri("/word/document.xml", UriKind.Relative)
Dim part As PackagePart
part = _package.CreatePart(_uri, "application/vnd.ms-word.main+xml")
Dim partWrt As StreamWriter
partWrt = New StreamWriter(part.GetStream(FileMode.Create, FileAccess.Write))
doc.Save(partWrt)
partWrt.Close()
_package.Flush()
'-- Step 3 - Create the relationship file
_uri = New Uri("/word/document.xml", UriKind.Relative)
Dim rel As PackageRelationship
rel = _package.CreateRelationship(_uri, TargetMode.Internal, _
"http://schemas.microsoft.com/office/2006/relationships/officeDocument", _
"rId1")
_package.Flush()
'-- Step 4- Close the document.
_package.Close()
End Sub
|
Create a private method “ReturnStream”
This method will take the document and return the file back.
Private Sub ReturnStream(ByVal filepath As String)
Dim iStream As System.IO.Stream
' Buffer to read 10K bytes in chunk:
Dim buffer(10000) As Byte
' Length of the file:
Dim length As Integer
' Total bytes to read:
Dim dataToRead As Long
' Identify the file to download including its path.
'filepath = "C:\OpenXML1\sanjay.docx"
' Identify the file name.
Dim filename As String = System.IO.Path.GetFileName(filepath)
Try
' Open the file.
iStream = New System.IO.FileStream(filepath, _
System.IO.FileMode.Open, IO.FileAccess.Read, _
IO.FileShare.Read)
' Total bytes to read:
dataToRead = iStream.Length
Response.ContentType = "application/vnd.ms-word.document.12"
'Response.ContentType = "application/octet-stream"
Response.AddHeader("Content-Disposition", _
"attachment; filename=" & filename)
' Read the bytes.
While dataToRead > 0
' Verify that the client is connected.
If Response.IsClientConnected Then
' Read the data in buffer
length = iStream.Read(buffer, 0, 10000)
' Write the data to the current output stream.
Response.OutputStream.Write(buffer, 0, length)
' Flush the data to the HTML output.
Response.Flush()
ReDim buffer(10000) ' Clear the buffer
dataToRead = dataToRead - length
Else
'prevent infinite loop if user disconnects
dataToRead = -1
End If
End While
Catch ex As Exception
' Trap the error, if any.
Response.Write("Error : " & ex.Message)
Finally
If IsNothing(iStream) = False Then
' Close the file.
iStream.Close()
End If
End Try
End Sub
|
Code for the event “GenerateDocument“
This will create a temp file and write the call the above two method to generate and return the file.
Protected Sub GenerateDocument_Click(ByVal sender As Object, _
ByVal e As System.EventArgs)
Handles GenerateDocument.Click
Dim filepath As String
Dim content As String
content = mleTextBox1.Text
filepath = Guid.NewGuid.ToString() + ".docx"
CreateFile(filepath, content)
ReturnStream(filepath)
End Sub
|
Build and Run
From the Build menu select “Build Web Site”
To run with out debug, select “Start Without Debugging” under “Debug” menu or press Ctrl+F5.
Web page you just created appears in the browser as shown below.
Key in some text and click on “Generate Document” button, a file download dialog appears. Use the Save option. Note: I had some issue in using the Open Option.
Note: remember the save in directory.
After the saving the Download Complete dialog will appear with an button to open the document. Use the option to view the document.
See the content you typed being displayed as a document.