Introduction
This article discusses how to set the style of your Word Document using a template file and an Excel File.
Styles name is saved in an Excel File, and style formation in a template file. Word Document is parsed, and depending on Search Text, MaxFinds, Style will be set.
How To Use Code
Use Com Word Reference:
I use lateBinding in Excel. There is no need to add reference.
Process in the Application
- First parse the Excel File, save Style in
ArrayList
. - Open Word Document.
- Apply Template File to Document.
- Parse Word Document Paragraph.
- Set Style to Paragraph:
- Check if the Paragraph Text contains the Search String
- Higher Priority for Upper Style names in Excel file
- Check If found Less Than Max
My.Settings.TemplateFilePath = txtTemplateFilePath.Text
My.Settings.ExcelStyleFilePath = txtExcleStylePath.Text
ErrorLog.Clear()
Dim excelParser As New OfficeModule.ExcelParser_
xcleStylePath.Text, "Formatting")
Dim iExcelStlyeCollection As System.Collections.ArrayList
iExcelStlyeCollection = excelParser.PasreExcelStyle()
bgWorker.ReportProgress(2)
If Not iExcelStlyeCollection Is Nothing Then
Dim wordPaser As New OfficeModule.WordParser_
rdPath.Text, txtTemplateFilePath.Text, bgWorker)
wordPaser.ExcelStyles = iExcelStlyeCollection
wordPaser.ParseWord()
e.Result = wordPaser.UnFoundStyle
Else
ProgressBar1.Value = ProgressBar1.Maximum
gridErrorLog.DataSource = ErrorLog.GetDataTableException()
End If
1. First Parse the Excel File
The priority of style will be for first rows.
Class ExcelStyle to save SearchString, Style Max Finds, Defaults:
Public Class ExcelStyle
Public Property SearchString() As String
Get
Return _searchString
End Get
Set(ByVal value As String)
_searchString = value
End Set
End Property
Public Property Style() As String
Get
Return _style
End Get
Set(ByVal value As String)
_style = value
End Set
End Property
Public Property Defaults() As String
Get
Return _defaults
End Get
Set(ByVal value As String)
_defaults = value
End Set
End Property
Public Property Founds() As Int64
Get
Return _currentFounds
End Get
Set(ByVal value As Int64)
_currentFounds = value
End Set
End Property
Public Property MaxFinds() As Int64
Get
Return _maxFinds
End Get
Set(ByVal value As Int64)
_maxFinds = value
End Set
End Property
Class ExcelParser is used to parse Excel sheet. Every row is added ExcelStyle
object and added to ArrayListCollection
.
Example of ExcelSheet:
Public Class ExcelParser
Public ExcelStylesList As System.Collections.ArrayList
Public Function PasreExcelStyle() As System.Collections.ArrayList
If IsExcelFile(FilePath) = True Then
Try
Dim xlApp As Object
Dim xlWorkBook As Object
Dim xlWorkSheet As Object
Dim range As Object
Dim Obj As Object
Dim rowIndex As Int64
xlApp = CreateObject("Excel.Application")
xlWorkBook = xlApp.Workbooks.Open(FilePath)
xlWorkSheet = xlWorkBook.Worksheets(ExcelSheet)
range = xlWorkSheet.UsedRange
If Not range Is Nothing Then
For rowIndex = range.Rows.Count To 2 Step -1
Dim excelStyle As New ExcelStyle
Obj = range.Cells(rowIndex, 1)
If Obj.value Is Nothing Then
excelStyle.SearchString = String.Empty
Else
excelStyle.SearchString = CStr(Obj.value)
End If
Obj = range.Cells(rowIndex, 2)
If Obj.value Is Nothing Then
excelStyle.Style = String.Empty
Else
excelStyle.Style = CStr(Obj.value)
End If
Obj = range.Cells(rowIndex, 3)
If Obj.value Is Nothing Then
excelStyle.MaxFinds = -1
Else
excelStyle.MaxFinds = Convert.ToInt64(Obj.value)
End If
Obj = range.Cells(rowIndex, 4)
If Obj.value Is Nothing Then
excelStyle.Defaults = -1
Else
excelStyle.Defaults = CStr(Obj.value)
End If
ExcelStylesList.Add(excelStyle)
Next
End If
releaseObject(xlApp)
releaseObject(xlWorkBook)
releaseObject(xlWorkSheet)
Return ExcelStylesList
Catch ex As Exception
Dim LogExc As New LogException(ex.Source, ex.Message)
ErrorLog.Add(LogExc)
Return Nothing
End Try
Else
Return Nothing
End If
End Function
2. Open Word Document
Import Word = Microsoft.Office.Interop.Word
Public Class WordParser
is used to parse the Word Document and set paragraph style depending on the ExcelStyle
collection.
Member of class:
Private ParagraphDefination As ParagraphSetting
Dim orgDoc As Word.Document
Private doc As Word.Document
Shared wordApp As Word.ApplicationClass
To run Word and Open Document:
Private Sub RunWord()
Try
If FilePath <> String.Empty And TemplePath <> String.Empty Then
Dim o_nullobject As Object = System.Reflection.Missing.Value
Dim o_filePath As Object = FilePath
Dim o_NewfilePath As Object
Dim NewFileName As String
NewFileName = FilePath.Substring(0, FilePath.LastIndexOf(".")) & _
"_Final." & FilePath.Substring(FilePath.LastIndexOf(".") + 1)
o_NewfilePath = NewFileName
Dim oFalse As Object = False
Dim oTrue As Object = True
If wordApp Is Nothing Then
wordApp = New Word.Application()
Else
wordApp = GetObject(Nothing, "Word.Application")
End If
orgDoc = wordApp.Documents.Open(o_filePath, o_nullobject, oFalse, _
o_nullobject, o_nullobject, o_nullobject, o_nullobject, _
o_nullobject, o_nullobject, o_nullobject, o_nullobject, _
oFalse, o_nullobject, o_nullobject, o_nullobject, o_nullobject)
orgDoc.SaveAs(NewFileName)
orgDoc.Close(oFalse)
releaseObject(orgDoc)
oTrue, o_nullobject, o_nullobject, o_nullobject, o_nullobject, _
o_nullobject, o_nullobject, o_nullobject, o_nullobject, oFalse, _
o_nullobject, o_nullobject, o_nullobject, o_nullobject)
doc = wordApp.Documents.Open(NewFileName, o_nullobject, oFalse, _
o_nullobject, o_nullobject, o_nullobject, o_nullobject, _
o_nullobject, o_nullobject, o_nullobject, o_nullobject, _
oFalse, o_nullobject, o_nullobject, o_nullobject, o_nullobject)
doc.CopyStylesFromTemplate(TemplePath)
ParagraphCount = doc.Paragraphs.Count - 1
End If
Catch ex As Exception
Dim LogExc As New LogException(ex.Source, ex.Message)
ErrorLog.Add(LogExc)
End Try
End Sub
3. Apply Template File to Document
There are two ways to apply Template Styles to Word Document:
First Way
doc = wordApp.Documents.Open(NewFileName, o_nullobject, oFalse, _
o_nullobject, o_nullobject, o_nullobject, o_nullobject, o_nullobject, _
o_nullobject, o_nullobject, o_nullobject, oFalse, o_nullobject, _
o_nullobject, o_nullobject, o_nullobject)
doc.CopyStylesFromTemplate(TemplePath)
Second Way
docTemplate = wordApp.Documents.Open(oTemplate, o_nullobject, oTrue, _
o_nullobject, o_nullobject, o_nullobject, o_nullobject, _
o_nullobject, o_nullobject, o_nullobject, o_nullobject, _
oFalse, o_nullobject, o_nullobject, o_nullobject, o_nullobject)
doc.AttachedTemplate = docTemplate
4. Parse Word Document Paragraph
Public Sub ParseWord()
Try
doc.Activate()
doc.UpdateStyles()
#If DEBUG Then
wordApp.Visible = True
doc.Application.Visible = True
#End If
ParseWordStyle()
wordApp.Visible = True
doc.Application.Visible = True
doc.Save()
Catch ex As Exception
Dim LogExc As New LogException(ex.Source, ex.Message)
ErrorLog.Add(LogExc)
backgroudWorker.CancelAsync()
Finally
Clear()
End Try
End Sub
5. Set Style to Paragraph
- Parsing Word to set styles
- Remove empty paragraph
- Remove extra spaces between words
- If paragraph contains table, it will be skipped
- Bullet will be set if not set by user
Private Sub ParseWordStyle()
Try
Dim i As Int64
Dim ParagraphCount As Int64
ParagraphCount = doc.Paragraphs.Count
i = 1
While i <= ParagraphCount
backgroudWorker.ReportProgress(1)
If doc.Paragraphs(i).Range.Tables.Count > 0 Then
ParagraphDefination = ParagraphSetting.Table
Else
Dim txt As String
txt = doc.Paragraphs(i).Range.Text
txt = txt.Trim("")
txt = txt.Trim()
If doc.Paragraphs(i).Range.Words.Count = 1 Or txt = "" _
Or txt = String.Empty Then
ParagraphDefination = ParagraphSetting.EmptyParagraph
Else
If doc.Paragraphs(i).Range.ListFormat.ListType = _
Word.WdListType.wdListNoNumbering Then
ParagraphDefination = ParagraphSetting.ParagaraphStyle
End If
If doc.Paragraphs(i).Range.ListFormat.ListType = _
Word.WdListType.wdListBullet Then
ParagraphDefination = ParagraphSetting.WdListBullet
End If
If doc.Paragraphs(i).Range.ListFormat.ListType = _
Word.WdListType.wdListSimpleNumbering Then
ParagraphDefination = ParagraphSetting.wdListSimpleNumbering
End If
If txt <> String.Empty Then
If txt.Substring(0, 1) = "-" Then
ParagraphDefination = ParagraphSetting.WdListBullet
Else
If txt.IndexOf(".") <> -1 Then
If IsNumeric(txt.Substring(0, txt.IndexOf("."))) = _
True Then
ParagraphDefination = _
ParagraphSetting.wdListSimpleNumbering
End If
End If
End If
End If
End If
End If
Select Case ParagraphDefination
Case ParagraphSetting.Table
Case ParagraphSetting.EmptyParagraph
doc.Paragraphs(i).Range.Delete()
ParagraphCount = ParagraphCount - 1
i = i - 1
Case ParagraphSetting.WdListBullet
RemoveExtraSpaces(doc.Paragraphs(i))
ListParagraphSettings(doc.Paragraphs(i), "BulletPoint")
Dim index As Object = 1
Dim myTemplate As Word.ListTemplate = wordApp.ListGalleries_
(Microsoft.Office.Interop.Word.WdListGalleryType._
wdBulletGallery).ListTemplates.Item(index)
With myTemplate.ListLevels(1)
.NumberFormat = "-"
.TrailingCharacter = Word.WdTrailingCharacter.wdTrailingTab
.StartAt = 0
End With
doc.Paragraphs(i).Range.ListFormat.ApplyListTemplate(myTemplate)
RemoveWritenBullets(doc.Paragraphs(i))
Case ParagraphSetting.wdListSimpleNumbering
RemoveExtraSpaces(doc.Paragraphs(i))
ListParagraphSettings(doc.Paragraphs(i), "Enumeration")
ParagraphStyleSetting(doc.Paragraphs(i))
Case ParagraphSetting.ParagaraphStyle
RemoveExtraSpaces(doc.Paragraphs(i))
ParagraphStyleSetting(doc.Paragraphs(i))
Case Else
RemoveExtraSpaces(doc.Paragraphs(i))
ParagraphStyleSetting(doc.Paragraphs(i))
End Select
i = i + 1
End While
Catch ex As Exception
Dim LogExc As New LogException(ex.Source, ex.Message)
ErrorLog.Add(LogExc)
End Try
End Sub
Set Style to paragraph from template file:
Private Sub ParagraphStyleSetting(ByVal Paragaph As Word.Paragraph)
Try
Dim exStyle As OfficeModule.ExcelStyle
Dim parsText As String
Dim iCollection As Int64
Dim lastFoundIndex As Int64
lastFoundIndex = -1
parsText = Paragaph.Range.Text
parsText = parsText.ToUpper()
For iCollection = 0 To ExcelStyles.Count - 1
exStyle = ExcelStyles(iCollection)
exStyle.SearchString = exStyle.SearchString.ToUpper()
exStyle.SearchString = FixSeacrhText(exStyle.SearchString)
If parsText.IndexOf(exStyle.SearchString) <> -1 Or _
exStyle.SearchString = "*" Then
If (exStyle.Founds < exStyle.MaxFinds) Or (exStyle.MaxFinds = -1) Then
lastFoundIndex = iCollection
End If
End If
Next
If lastFoundIndex <> -1 Then
exStyle = ExcelStyles(lastFoundIndex)
If SetStyleParagraph(Paragaph, exStyle.Style) = True Then
exStyle.Founds = exStyle.Founds + 1
End If
End If
Catch ex As Exception
Dim LogExc As New LogException(ex.Source, ex.Message)
ErrorLog.Add(LogExc)
End Try
End Sub
Private Function SetStyleParagraph(ByVal Paragaph As Word.Paragraph, _
ByVal Style As String) As Boolean
Dim isSetStyle As Boolean = False
Style = FixStyleText(Style)
If Paragaph.Style.NameLocal <> Style Then
Try
If IsStylExsist(Style) Then
Paragaph.Style = Style
isSetStyle = True
End If
Catch ex As Exception
isSetStyle = False
Dim LogExc As New LogException(ex.Source, ex.Message)
ErrorLog.Add(LogExc)
End Try
End If
Return isSetStyle
End Function
Almost Done
You will see more details in the source file on parsing and setting Styles to document.
The following things are not explained in the article:
- Process will be done in async Mode. I used Backgroundworker and passed by reference to class
WordParser
. - Late binding of Excel Object. See this link.
- I have tired to use LateBinding to Word com but objects like the paragraph object can't be set by value. I notice that it's a bug in using Com in .NET.
- Error logs done by using shared
ArrayList
which will be used in all class objects.
Public Class ErrorLog
Private Shared _logException As New System.Collections.ArrayList
Private Shared Property LogException() As System.Collections.ArrayList
Get
Return _logException
End Get
Set(ByVal value As System.Collections.ArrayList)
_logException = value
End Set
End Property
Public Shared Sub Add(ByVal LogExcp As LogException)
LogException.Add(LogExcp)
End Sub
Public Shared Function GetDataTableException() As System.Data.DataTable
Dim dt As New System.Data.DataTable
Dim iCollection As Int64
dt.Columns.Add(New DataColumn("Source", GetType(String)))
dt.Columns.Add(New DataColumn("Message", GetType(String)))
For iCollection = 0 To LogException.Count - 1
Dim LogExc As LogException = LogException(iCollection)
Dim row As System.Data.DataRow
row = dt.NewRow()
row("Source") = LogExc.Source
row("Message") = LogExc.Message
dt.Rows.Add(row)
Next
Return dt
End Function
- You can modify Errors Reporting with whatever you need, writing to XML, text file, Event log of window.
- WinWord.exe will still be running in the background. I can't kill a process because the user might still want to modify the opened document.
- Examples of Word, Excel, template file are included in the source code.
History
- 26th March, 2009: Initial version