Word Style Automation
Set Style of Word Document from Template
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
''Saving value in App Setting to Get Values When Run Application again
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
''ExcelStyle Object Add To Collection
'' Public ExcelStylesList As System.Collections.ArrayList
Public ExcelStylesList As System.Collections.ArrayList
''Late Biding for Excel Sheet
''No Need To Add reference to Project
''Reading the values From Bottom to top
''Priority for Top Rows
''* Will be for all paragraphs
Public Function PasreExcelStyle() As System.Collections.ArrayList
If IsExcelFile(FilePath) = True Then
Try
Dim xlApp As Object 'Application
Dim xlWorkBook As Object 'Workbook
Dim xlWorkSheet As Object 'Worksheet
Dim range As Object 'Range
Dim Obj As Object
Dim rowIndex As Int64
xlApp = CreateObject("Excel.Application")
xlWorkBook = xlApp.Workbooks.Open(FilePath)
xlWorkSheet = xlWorkBook.Worksheets(ExcelSheet)
''The cells Have Data
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) ''SearchString Cell
If Obj.value Is Nothing Then
excelStyle.SearchString = String.Empty
Else
excelStyle.SearchString = CStr(Obj.value)
End If
Obj = range.Cells(rowIndex, 2) ''Style Cell
If Obj.value Is Nothing Then
excelStyle.Style = String.Empty
Else
excelStyle.Style = CStr(Obj.value)
End If
Obj = range.Cells(rowIndex, 3) ''MaxFound Cell
If Obj.value Is Nothing Then
excelStyle.MaxFinds = -1
Else
excelStyle.MaxFinds = Convert.ToInt64(Obj.value)
End If
Obj = range.Cells(rowIndex, 4) ''Defaults
If Obj.value Is Nothing Then
excelStyle.Defaults = -1
Else
excelStyle.Defaults = CStr(Obj.value)
End If
ExcelStylesList.Add(excelStyle)
Next
End If
'' xlWorkBook.Close()
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 ''To Load Word Document
Private doc As Word.Document 'To Load Word Document in new File Object
''Private docTemplate As Word.Document ''Object
Shared wordApp As Word.ApplicationClass '' Object 'Application
To run Word and Open Document:
''Run Word Exe
''Set Document Object
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 oTemplate As Object = TemplePath
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
''Create Word Application Object
If wordApp Is Nothing Then
wordApp = New Word.Application()
Else
''To not create more than one instance of word Application
''When You Run process more than once
wordApp = GetObject(Nothing, "Word.Application")
End If
''Open word Document With File Path
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)
''doc = orgDoc ''try to open it in new document
orgDoc.Close(oFalse)
releaseObject(orgDoc)
''Open Template DOT ,DOTX
'' 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 ''Set Template Document
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) ''oTHER Way To Load Style
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()
''TO Update Style from Template Document
doc.UpdateStyles()
''word Application will be visible if you are in Debug Mode
#If DEBUG Then
wordApp.Visible = True
doc.Application.Visible = True
'' docTemplate.ActiveWindow.Visible = False
#End If
''Parsing process
ParseWordStyle()
wordApp.Visible = True
doc.Application.Visible = True
'' docTemplate.ActiveWindow.Visible = False
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
''When Delete Paragraph It remove From Collection ,Counter Must be set
ParagraphCount = doc.Paragraphs.Count
i = 1
''For beginner Levels All coms Collection First Index is 1
While i <= ParagraphCount
''To Increase progressBar by 1
backgroudWorker.ReportProgress(1)
''Image will not take style
'Paragraph Settings
'Priority as Follows
''Check if paragraph contains Table
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()
''Check Empty Paragraph
If doc.Paragraphs(i).Range.Words.Count = 1 Or txt = "" _
Or txt = String.Empty Then '' String.Empty For Empty
'' Paragraph will be Deleted
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
''Seeing If user missed up without using enum or bullet
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
'Skip Table Style
Case ParagraphSetting.EmptyParagraph
doc.Paragraphs(i).Range.Delete() 'Delete Empty Paragraph
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 '1.2.3.4'
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 ''whatever case
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)
'' backgroudWorker.CancelAsync()
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 ''Text In paragraph
parsText = parsText.ToUpper() ''to match Upper And Lower case
For iCollection = 0 To ExcelStyles.Count - 1 ''Looping throw
''Excel Setting Object
exStyle = ExcelStyles(iCollection)
exStyle.SearchString = exStyle.SearchString.ToUpper()
exStyle.SearchString = FixSeacrhText(exStyle.SearchString) ' To ensure
' correct inputs
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 ''Collection Of styles
''Index Of Object Style
If lastFoundIndex <> -1 Then
exStyle = ExcelStyles(lastFoundIndex)
''Check If the Style exists In Document Before
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
''Set Style to paragraph from template file
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 'Ensure Style exists in Template Document
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