Create a Word Glossary
Microsoft Word has a large number of really useful automation tools when it comes to inserting reference tables such as Contents, Index or a Table of Authorities. One thing that it really lacks however is a good glossary function.
A document I’m working on at work requires a glossary and rather than scan through the whole document, trying to identify every term or acronym that might need an explanation and then manually writing one out at the end of the document, I decided to mark relevant reference terms in the same way as you might for an index.
The Table of Authorities is probably one of the least-used (and least understood) tables in Word. It is most commonly used in the legal and public sector industries, but very little outside of those. However it also a really useful multi-purpose table. Word 2007 provides a little more by way of functionality (providing a Bibliography in addition to the other references), but still the glossary is missing.
So let’s create our glossary using the Table of Authorities. What we’re going to do is create a garden-variety TOA first, and then apply a bit of VBA to tidy up the automatically-inserted page number references.
Step 1 - Creating the Table of Authorities (TOA)
The TOA needs to be made up of a collection of marked citations. You mark a citation by pressing
and clicking the Mark Citation… button. For each term that you want a glossary entry, mark an occurrence of that term in your document and then enter a description in the “Selected text:” area.
Once you’ve marked all the entries you want (you can add more later as required), go to the end of your document (or wherever it is that you want to insert your glossary) and navigate through Insert > Reference > Index and Tables, select the Table of Authorities tab and click OK. A TOA is automatically inserted into your document.
Step 2 - Formatting the TOA
A TOA by default has page references to any citation in your document. Glossaries don’t need page numbers so we’re going to want to remove these. The default TOA also has tab leaders and a heading which are surplus to requirements. We’ll want to change the field values for the TOA and then apply some code to remove the page numbers.
If you right-click on the TOA you will see a context menu, of which one of the options is “Toggle Field Codes”. Select this menu item and your TOA will become:
{ TOA \h \c “1″ \p }
In Word speak, this means “insert a Table of Authorities” { TOA; “include a heading” \h; “include items from category 1″ (i.e. the “All” category) \c “3″; and “use passim” \p. We want to modify this field slightly so that it says:
{ TOA \c “1″ \e “” }
In other words, “insert a Table of Authorities”; “include items from category 1″; “end entries with a blank / empty tab leader”.
If you right-click on the field and choose “Toggle Field Codes” again, press
Step 3 - Some Code to Remove Page Numbers
Now here’s the complicated part: Word will automatically insert page number references regardless of the type of index or table you create. We need to remove these references programatically. As nice as it would be to be able to remove these numbers either through a switch in the field’s markup or possibly through page formatting, unfortunately this is not possible. So we’re going to need to include a VBA macro to take that stuff out.
I’ll look at the code for this in part 2 of this blog next week.
Create a Word Glossary - Part 2
A couple of weeks ago, I looked at how to create a Glossary in Microsoft Word. While a little late (and my apologies to John and others for the delay), here is the second part to that post where we look at how to automatically remove pages numbers from the Word-generated Table of Authorities (TOA).
While we can get 90% of the way there, we still need some VBA automation in order to remove the automatically-inserted page numbers (not really of any use in a glossary).
Step 1 - Making friends : application & document awareness
Our first task is to create a Class Module in our Word macro that can “listen” to events within the main document body. Let’s start by pressing
- We want to respond to events.
- We need an application variable (declared with WithEvents) to receive the events.
- We need a class module to serve as a container for the application variable.
Let’s set this up by adding a class module called ThisApplication. Right-click on the document project in the Project Explorer and select Insert -> Class Module (note that it’s the class module we’re after). Rename the new module to “ThisApplication”. Then, below the Option Explicit declaration we’ll include the following line of code:
Public WithEvents App As Word.Application
That’s it. Done. Next we need a module whose responsibility is to recognise the document currently in use and listen for any time the document’s fields are updated.
Step 2 - Listen closely : wiring up the application’s UpdateChanges event
First things first. Let’s create that new module we were just talking about. Right-click the Project and select Insert -> Module (just your regular, garden-variety module this time) and rename it to something meaningful. I would suggest Glossary or something along those lines. This is where all the action happens. Your Project should now resemble something similar (i.e. very similar) to the list of files you can see in the image on the right (highlighted yellow, for your convenience).
The first task for this module is going to be to get a reference to the Application whose events we have previously decided we’ll be listening to. Enter the following code after Option Explicit:
Dim MyApplication As New ThisApplication
That defines a container for our application. Let’s actually tell it what to put in there:
Public Sub AutoExec()
Set MyApplication.App = Word.Application
End Sub
Easy. Now we need to tell Word what to do when the user updates the TOA. Oddly enough, there is no explicitly-defined event for fields updating (e.g. OnFieldUpdating()) in the Word object model. There is something we can use however: Word has an UpdateFields method that we can piggyback off to include our own code. Let’s see how that would look:
' Override Word's native UpdateFields property
Public Sub UpdateFields()
Dim docThis As Word.Document
Dim TOA As TableOfAuthorities
Dim parEntry As Paragraph
' Make sure we're working with the currently active document
Set docThis = ThisDocument
' Step through the Table of Authorities in the document
For Each TOA In docThis.TablesOfAuthorities
TOA.Update ' Update the Table of Authorities to include any newly-marked items
' Step through each entry in the Table of Authorities
For Each parEntry In TOA.Range.Paragraphs
StripPageNumbers parEntry ' Call our StripPageNumbers routine
Next
Next
' Don't forget to clean up!
Set docThis = Nothing
End Sub
That’s about it. Let’s look at what we’ve just done here.
We’re working with three objects in the UpdateFields method: docThis (our Document), TOA (our Table of Authorities) and parEntry (the entries in the TOA). The first task is to get a handle on the current document (Set docThis = ThisDocument). Then, for each Table of Authorities in our document, we want to step through each paragraph and strip the numbers from the end of that entry.
Please note at this point that if you’re already using Tables of Authorities in other places, you’ll want to replace the For Each loop with:
Set TOA = docThis.TableOfAuthorities(x)
Where x is the 1-based index number of the TOA (i.e. the order in which your desired TOA appears in the document relative to other TOAs).
Step 3 - Strip! : Remove numeric values from End of Line
Ok. The last thing we need to do is actually get rid of those page numbers! You will have noticed the StripPageNumbers call from the code snippet above. This is the actual code for that method:
' Removes any number from the end of a paragraph
Private Sub StripPageNumbers(ByRef Para As Paragraph)
' Make sure we have at least one word in our paragraph (a new line counts as one word, remember).
If Para.Range.Words.Count > 1 Then
' Loop until you can't find a number at the end.
Do While IsNumeric(Para.Range.Words(Para.Range.Words.Count - 1))
Para.Range.Words(Para.Range.Words.Count - 1).Delete
Loop
' Also check to ensure that the last word doesn't have a page number against it
' if the user has forgotten to include a fullstop at the end of the description
Do While IsNumeric(Para.Range.Characters(Len(Para.Range) - 1))
Para.Range.Characters(Len(Para.Range) - 1).Delete
Loop
End If
End Sub
Again, let’s look at what we’ve accomplished here. The StripPageNumbers method takes one parameter, Para, which is of type Paragraph. As long as that paragraph is not empty, we check the last word to see if it is a number and if so, we remove it. We then repeat this process for cases where there is no full-stop at the end of a definition.
And we’re done!
A download of the code in this example can be found below. Let me know if this post was useful to you or if you have found any bugs or glitches with my approach. Also - let me know if there are other aspects or problems with Microsoft Office products that you could use some help on.
http://www.shaunakelly.com/word/glossary/glossary.html
ReplyDelete