
Update 3/2/11: The Wordnik API has been updated, and this code has not. I will be updating it as time permits. –JP
Wordnik is an API I discovered recently while browsing the Internet for APIs. What is Wordnik?
Wordnik is a place for all the words, and everything known about them.
Our goal is to show you as much information as possible, as fast as we can find it, for every word in English, and to give you a place where you can make your own opinions about words known.
Basically it's a dictionary, with an API so your applications can consume information about words, their definitions, sample sentences, and related words. This page will explore the available methods you can use to extract information from the API using VBA. You'll also find a sample application for Microsoft® Word.
As with many other API services, you'll need an API key to work with Wordnik's API. Visit the signup page to apply for one. I have my own API key, but in my code samples it has been removed.
Note that in the samples below, the API key is passed in the headers. Wordnik has since changed their API to allow passing the API key in the GET request. So you can do it as I have done, or change the code to send the API key in the request URL.
In all of the following code samples, I have declared objects As Object to avoid early binding issues. You should have msxml2.dll in your system32 directory. I did, however, preserve the early bound references so you can see how the objects would be declared if the code was early bound.
Also note that some of these methods may not be full implementations of the associated API method. For example, I might leave out some parameters that would otherwise change the output of the API.
To use some of the methods below, you'll need to first paste the following Enum section into a standard module (placed at the top), or into their own module. I prefer to put them into their own module so all Enums are in the same place and there are no placement issues.
Public Enum partOfSpeech noun Verb adjective adverb idiom article abbreviation preposition Prefix interjection suffix End Enum Public Enum wordType synonym antonym form equivalent hyponym variantType End Enum
These are used by the GetDefinition and GetRelatedWords functions to get the proper part of speech and word type for a given word. You'll also need to copy the helper functions and place them into a standard module in the same project, since they are used by all of the functions below.
The GetWord Function
This function simply looks up a given word and returns that word. It is meant to verify that a given word is actually a word (as found in the Wordnik dictionary, of course). The perfect application I can think of for this is a Scrabble-type application, to verify that a submitted word is real.
It uses some of the more common techniques we've seen in articles like Airport Information, namely
- checking for an existing XML file before (re-)querying the web,
- grabbing a XML response from an API, and
- parsing a temporary XML document for (a) sought after value(s) using the MSMXL object model.
Function GetWord(word As String, apiKey As String) As String
Dim xml As Object ' MSXML2.XMLHTTP
Dim result As String
Dim tempFile As String
Dim xmlDoc As Object ' MSXML2.DOMDocument
Dim xmlDocRoot As Object ' MSXML2.IXMLDOMNode
Dim wordNode As Object ' MSXML2.IXMLDOMNodeList
tempFile = environ("temp") & "\" & word & ".xml"
' requery website if file doesn't exist
If Len(Dir(tempFile)) = 0 Then
Set xml = GetMSXML
xml.Open "GET", "http://api.wordnik.com/api/word.xml/" & word, False
xml.setRequestHeader "api_key", apiKey
xml.Send
result = xml.responsetext
' create XML file from result
Call CreateFile(tempFile, result)
End If
' open XML file
Set xmlDoc = GetDomDoc
With xmlDoc
.async = False
.validateOnParse = False
.Load tempFile
End With
' check that the XML doc loaded
If LoadError(xmlDoc) Then
Exit Function
End If
' get root node
Set xmlDocRoot = GetRootNode(xmlDoc)
' get first level child nodes
Set wordNode = GetChildNodes(xmlDocRoot)
' grab word
GetWord = wordNode.Item(1).nodeTypedValue
End FunctionThrough experimentation (and by suggestion of Wordnik's API documentation), the API key is passed by header instead of in the HTTP GET request. Otherwise the function is similar to those we've seen in the article previously mentioned.
Sample usage
Sub TestGetWord() Dim apiKey As String Dim word As String apiKey = "your API key here" word = "blather" Debug.Print GetWord(word, apiKey) ProgramExit: Exit Sub ErrorHandler: MsgBox Err.Number & " - " & Err.Description Resume ProgramExit End Sub
The GetDefinition Function
This function takes a given word, the part of speech and number of results desired and returns them as a String. The API returns all parts of speech, so we need to parse the XML for the one we want and only return results from that. Part of speech and number of results are passed as headers to the API.
Function GetDefinition(word As String, apiKey As String, _
Optional partOfSpeech As partOfSpeech = noun, _
Optional numberOfResults As Long = 1) As String
Dim xml As Object
Dim result As String
Dim pos As String
Dim i As Long
Dim tempFile As String
Dim xmlDoc As Object ' MSXML2.DOMDocument
Dim xmlDocRoot As Object ' MSXML2.IXMLDOMNode
Dim definitionNodes As Object ' MSXML2.IXMLDOMNodeList
Dim definitionNode As Object ' MSXML2.IXMLDOMNode
tempFile = environ("temp") & "\" & word & "_definition.xml"
pos = GetPartOfSpeech(partOfSpeech)
' requery website if file doesn't exist
If Len(Dir(tempFile)) = 0 Then
Set xml = GetMSXML
xml.Open "GET", "http://api.wordnik.com/api/word.xml/" & word & "/definitions", False
xml.setRequestHeader "api_key", apiKey
xml.setRequestHeader "partOfSpeech", pos
xml.setRequestHeader "limit", numberOfResults
xml.Send
result = xml.responsetext
' create XML file from result
Call CreateFile(tempFile, result)
End If
' open XML file
Set xmlDoc = GetDomDoc
With xmlDoc
.async = False
.validateOnParse = False
.Load tempFile
End With
' check that the XML doc loaded
If LoadError(xmlDoc) Then
Exit Function
End If
' get root node
Set xmlDocRoot = GetRootNode(xmlDoc)
' get first level child nodes
Set definitionNodes = GetChildNodes(xmlDocRoot)
' look for correct part of speech
For i = 1 To definitionNodes.Length
Set definitionNode = definitionNodes.Item(i - 1)
If definitionNode.childNodes(3).nodeTypedValue = pos Then
GetDefinition = definitionNode.childNodes(1).nodeTypedValue
Exit For
End If
Next i
End FunctionSample usage
Sub TestGetDefinition() Dim apiKey As String Dim word As String apiKey = "your API key here" word = "tissue" Debug.Print GetDefinition(word, apiKey, noun) ProgramExit: Exit Sub ErrorHandler: MsgBox Err.Number & " - " & Err.Description Resume ProgramExit End Sub
The GetRelatedWords Function
This function returns a String array of words related to the word passed to the function. It can return any of the following word types (per the Enum):
- synonym
- antonym
- form
- equivalent
- hyponym
- variant
Function GetRelatedWords(word As String, apiKey As String, _
Optional wordType As wordType = synonym, _
Optional numberOfResults As Long = 1) As String()
Dim xml As Object
Dim result As String
Dim wdType As String
Dim tempFile As String
Dim i As Long, j As Long
Dim tempRelatedWords() As String
Dim xmlDoc As Object ' MSXML2.DOMDocument
Dim xmlDocRoot As Object ' MSXML2.IXMLDOMNode
Dim wordstrings As Object ' MSXML2.IXMLDOMNodeList
Dim wordstring As Object ' MSXML2.IXMLDOMNodeList
tempFile = environ("temp") & "\" & word & "_related.xml"
wdType = GetWordType(wordType)
' requery website if file doesn't exist
If Len(Dir(tempFile)) = 0 Then
Set xml = GetMSXML
xml.Open "GET", "http://api.wordnik.com/api/word.xml/" & word & "/related", False
xml.setRequestHeader "api_key", apiKey
xml.setRequestHeader "type", wdType
xml.setRequestHeader "count", numberOfResults
xml.Send
result = xml.responsetext
' create XML file from result
Call CreateFile(tempFile, result)
End If
' open XML file
Set xmlDoc = GetDomDoc
With xmlDoc
.async = False
.validateOnParse = False
.Load tempFile
End With
' check that the XML doc loaded
If LoadError(xmlDoc) Then
Exit Function
End If
' get root node
Set xmlDocRoot = GetRootNode(xmlDoc)
' get first level child nodes
Set wordstrings = GetChildNodes(xmlDocRoot)
' find the correct type
For i = 1 To wordstrings.Length
If wordstrings.Item(i - 1).Attributes.getNamedItem("relType").nodeTypedValue = wdType Then
Set wordstring = wordstrings.Item(i - 1).childNodes
ReDim tempRelatedWords(1 To wordstring.Item(i - 1).childNodes.Length)
' write words to temp array
For j = 1 To wordstring.Item(i - 1).childNodes.Length
tempRelatedWords(j) = wordstring.Item(0).childNodes.Item(j - 1).nodeTypedValue
Next j
Exit For
End If
Next i
GetRelatedWords = tempRelatedWords
End FunctionSample usage
Sub TestGetRelated()
Dim apiKey As String
Dim word As String
Dim tempString() As String
Dim i As Long
apiKey = "your API key here"
word = "vexatious"
tempString = GetRelatedWords(word, apiKey)
For i = LBound(tempString) To UBound(tempString)
Debug.Print tempString(i)
Next i
ProgramExit:
Exit Sub
ErrorHandler:
MsgBox Err.Number & " - " & Err.Description
Resume ProgramExit
End SubThe GetWordFrequency Function
This function will return the frequency that a word appears in the Wordnik dictionary. Don't ask me what that means; I just work here ![]()
The API returns a few XML nodes with irrelevant information, so it has to be carefully parsed out. Unfortunately that means looping through the nodes twice; once to count the number of nodes (to size the array accordingly), then again to actually extract from the appropriate nodes.
Function GetWordFrequency(word As String, apiKey As String) As String()
Dim xml As Object
Dim result As String
Dim tempFile As String
Dim tempFreq() As String
Dim i As Long
Dim xmlDoc As Object ' MSXML2.DOMDocument
Dim xmlDocRoot As Object ' MSXML2.IXMLDOMNode
Dim frequencies As Object ' MSXML2.IXMLDOMNodeList
Dim frequency As Object ' MSXML2.IXMLDOMNodeList
Dim frequencyCount As Long
tempFile = environ("temp") & "\" & word & "_frequency.xml"
' requery website if file doesn't exist
If Len(Dir(tempFile)) = 0 Then
Set xml = GetMSXML
xml.Open "GET", "http://api.wordnik.com/api/word.xml/" & word & "/frequency", False
xml.setRequestHeader "api_key", apiKey
xml.Send
result = xml.responsetext
' create XML file from result
Call CreateFile(tempFile, result)
End If
Set xmlDoc = GetDomDoc
With xmlDoc
.async = False
.validateOnParse = False
.Load tempFile
End With
' check that the XML doc loaded
If LoadError(xmlDoc) Then
Exit Function
End If
' get root node
Set xmlDocRoot = GetRootNode(xmlDoc)
' get first level child nodes
Set frequencies = GetChildNodes(xmlDocRoot)
' count the number of nodes named "frequency"
' there are extra nodes w/ useless info
For i = 1 To frequencies.Length
If frequencies.Item(i - 1).nodeName = "frequency" Then
frequencyCount = frequencyCount + 1
End If
Next i
' resize array
ReDim tempFreq(1 To frequencyCount, 1 To 2)
' loop
For i = 1 To frequencies.Length
Set frequency = frequencies.Item(i - 1).childNodes
If frequencies.Item(i - 1).nodeName = "frequency" Then
tempFreq(i, 1) = frequency.Item(0).nodeTypedValue
tempFreq(i, 2) = frequency.Item(1).nodeTypedValue
End If
Next i
GetWordFrequency = tempFreq
End FunctionSample usage
Sub TestGetFrequency()
Dim apiKey As String
Dim word As String
Dim tempString() As String
Dim i As Long
apiKey = "your API key here"
word = "litigious"
tempString = GetWordFrequency(word, apiKey)
For i = LBound(tempString) To UBound(tempString)
Debug.Print tempString(i, 1) & tempString(i, 2)
Next i
ProgramExit:
Exit Sub
ErrorHandler:
MsgBox Err.Number & " - " & Err.Description
Resume ProgramExit
End SubThe GetPunctuationFactor Function
This function returns the number of times the given word appears with punctuation in the Wordnik dictionary. I think.
Function GetPunctuationFactor(word As String, apiKey As String) As String()
Dim xml As Object
Dim result As String
Dim tempFile As String
Dim i As Long
Dim tempString() As String
Dim xmlDoc As Object ' MSXML2.DOMDocument
Dim xmlDocRoot As Object ' MSXML2.IXMLDOMNode
Dim punctuationNodes As Object ' MSXML2.IXMLDOMNodeList
tempFile = environ("temp") & "\" & word & "_punctuation.xml"
' requery website if file doesn't exist
If Len(Dir(tempFile)) = 0 Then
Set xml = GetMSXML
xml.Open "GET", "http://api.wordnik.com/api/word.xml/" & word & "/punctuationFactor", False
xml.setRequestHeader "api_key", apiKey
xml.Send
result = xml.responsetext
' create XML file from result
Call CreateFile(tempFile, result)
End If
Set xmlDoc = GetDomDoc
With xmlDoc
.async = False
.validateOnParse = False
.Load tempFile
End With
' check that the XML doc loaded
If LoadError(xmlDoc) Then
Exit Function
End If
' get root node
Set xmlDocRoot = GetRootNode(xmlDoc)
' get first level child nodes
Set punctuationNodes = GetChildNodes(xmlDocRoot)
ReDim tempString(1 To punctuationNodes.Length)
For i = 1 To punctuationNodes.Length
tempString(i) = punctuationNodes.Item(i - 1).nodeTypedValue
Next i
GetPunctuationFactor = tempString
End FunctionSample usage
Sub TestPunctuationFactor()
Dim apiKey As String
Dim word As String
Dim tempString() As String
Dim i As Long
apiKey = "your API key here"
word = "blather"
tempString = GetPunctuationFactor(word, apiKey)
For i = LBound(tempString) To UBound(tempString)
Debug.Print tempString(i)
Next i
ProgramExit:
Exit Sub
ErrorHandler:
MsgBox Err.Number & " - " & Err.Description
Resume ProgramExit
End SubThe GetWordExamples Function
This function will return a String array of example sentences for a given word. I chose not to do so, but with a bit of tweaking of this function you can also return the source document name and URL to your VBA program.
Function GetWordExamples(word As String, apiKey As String) As String()
Dim xml As Object
Dim result As String
Dim tempFile As String
Dim i As Long
Dim tempString() As String
Dim xmlDoc As Object ' MSXML2.DOMDocument
Dim xmlDocRoot As Object ' MSXML2.IXMLDOMNode
Dim examples As Object ' MSXML2.IXMLDOMNodeList
tempFile = environ("temp") & "\" & word & "_examples.xml"
' requery website if file doesn't exist
If Len(Dir(tempFile)) = 0 Then
Set xml = GetMSXML
xml.Open "GET", "http://api.wordnik.com/api/word.xml/" & word & "/examples", False
xml.setRequestHeader "api_key", apiKey
xml.Send
result = xml.responsetext
' create XML file from result
Call CreateFile(tempFile, result)
End If
Set xmlDoc = GetDomDoc
With xmlDoc
.async = False
.validateOnParse = False
.Load tempFile
End With
' check that the XML doc loaded
If LoadError(xmlDoc) Then
Exit Function
End If
' get root node
Set xmlDocRoot = GetRootNode(xmlDoc)
' get first level child nodes
Set examples = GetChildNodes(xmlDocRoot)
' resize array
ReDim tempString(1 To examples.Length)
For i = 1 To examples.Length
tempString(i) = examples.Item(i - 1).childNodes(0).nodeTypedValue
Next i
GetWordExamples = tempString
End FunctionSample usage
Sub TestGetExamples()
Dim apiKey As String
Dim word As String
Dim tempString() As String
Dim i As Long
apiKey = "your API key here"
word = "blather"
tempString = GetWordExamples(word, apiKey)
For i = LBound(tempString) To UBound(tempString)
Debug.Print tempString(i)
Next i
ProgramExit:
Exit Sub
ErrorHandler:
MsgBox Err.Number & " - " & Err.Description
Resume ProgramExit
End SubThe AutoCompleteWord Function
A useful function indeed; this one takes a word fragment and returns a list of possible matches. Like the GetWordFrequency function, this one has extra information which needs to be carefully sidestepped to extract what we're really looking for.
Function AutoCompleteWord(wordFragment As String, apiKey As String, _
Optional numberOfResults As Long = 5, Optional startAt As Long = 1) As String()
Dim xml As Object
Dim result As String
Dim tempFile As String
Dim i As Long
Dim tempString() As String
Dim xmlDoc As Object ' MSXML2.DOMDocument
Dim xmlDocRoot As Object ' MSXML2.IXMLDOMNode
Dim matches As Object ' MSXML2.IXMLDOMNodeList
tempFile = environ("temp") & "\" & wordFragment & "_autocomplete.xml"
' requery website if file doesn't exist
If Len(Dir(tempFile)) = 0 Then
Set xml = GetMSXML
xml.Open "GET", "http://api.wordnik.com/api/suggest.xml/" & wordFragment, False
xml.setRequestHeader "api_key", apiKey
xml.setRequestHeader "limit", numberOfResults
xml.setRequestHeader "skip", startAt
xml.Send
result = xml.responsetext
' create XML file from result
Call CreateFile(tempFile, result)
End If
Set xmlDoc = GetDomDoc
With xmlDoc
.async = False
.validateOnParse = False
.Load tempFile
End With
' check that the XML doc loaded
If LoadError(xmlDoc) Then
Exit Function
End If
' get root node
Set xmlDocRoot = GetRootNode(xmlDoc)
' get first level child nodes
Set matches = GetChildNodes(xmlDocRoot)
' resize array
ReDim tempString(1 To matches.Length)
' loop
For i = 1 To matches.Length
' there are two different types of nodes!
If matches.Item(i - 1).nodeName = "match" Then
tempString(i) = matches.Item(i - 1).childNodes(1).nodeTypedValue
Else
tempString(i) = matches.Item(i - 1).nodeTypedValue
End If
Next i
AutoCompleteWord = tempString
End FunctionSample usage
Sub TestAutoCompleteWord()
Dim apiKey As String
Dim word As String
Dim tempString() As String
Dim i As Long
apiKey = "your API key here"
word = "bla"
tempString = AutoCompleteWord(word, apiKey)
For i = LBound(tempString) To UBound(tempString)
Debug.Print tempString(i)
Next i
ProgramExit:
Exit Sub
ErrorHandler:
MsgBox Err.Number & " - " & Err.Description
Resume ProgramExit
End SubThe GetWordOfTheDay Function
This function returns Wordnik's word of the day. If the function has already been run on a given day, the same word is returned (because the existing XML file will be used instead of re-querying the API, and, uh, also because the word of the day is the same for the whole day!). The API also returns sample sentences and definitions for the word.
Function GetWordOfTheDay(apiKey As String) As String()
Dim xml As Object
Dim result As String
Dim tempFile As String
Dim tempWord() As String
Dim i As Long
Dim xmlDoc As Object ' MSXML2.DOMDocument
Dim xmlDocRoot As Object ' MSXML2.IXMLDOMNode
Dim lowerNodes As Object ' MSXML2.IXMLDOMNodeList
tempFile = environ("temp") & "\wordnik_wordoftheday" & Format(Date, "mmddyyyy") & ".xml"
' if XML file exists, don't requery website
If Len(Dir(tempFile)) = 0 Then
Set xml = GetMSXML
xml.Open "GET", "http://api.wordnik.com/api/wordoftheday.xml", False
xml.setRequestHeader "api_key", apiKey
xml.Send
result = xml.responsetext
' create XML file from result
Call CreateFile(tempFile, result)
End If
Set xmlDoc = GetDomDoc
With xmlDoc
.async = False
.validateOnParse = False
.Load tempFile
End With
' check that the XML doc loaded
If LoadError(xmlDoc) Then
Exit Function
End If
' get root node
Set xmlDocRoot = GetRootNode(xmlDoc)
' get first level child nodes
Set lowerNodes = GetChildNodes(xmlDocRoot)
' size array
ReDim tempWord(1 To lowerNodes.Length)
' insert values into array
For i = 1 To lowerNodes.Length
tempWord(i) = lowerNodes.Item(i - 1).nodeTypedValue
Next i
GetWordOfTheDay = tempWord
End FunctionSample usage
Sub TestWordOfTheDay()
Dim apiKey As String
Dim word As String
Dim tempString() As String
Dim i As Long
apiKey = "your API key here"
word = "blather"
tempString = GetWordOfTheDay(apiKey)
For i = LBound(tempString) To UBound(tempString)
Debug.Print tempString(i)
Next i
ProgramExit:
Exit Sub
ErrorHandler:
MsgBox Err.Number & " - " & Err.Description
Resume ProgramExit
End SubThe GetRandomWord Function
The GetRandomWord function returns a randomly selected word from the Wordnik dictionary. It has three parameters:
- the API key,
- the length of the word (from 6 to 15 characters
- return only results that have a dictionary definition (true/false), and
In response to a request from Tim Falk in the Wordnik Google Group (as well as new information from Wordnik themselves), the GetRandomWord has been amended to not cache queries.
Function GetRandomWord(apiKey As String, Optional wordLength As Long, _
Optional hasDictionaryDef As Boolean = True) As String
Dim xml As Object
Dim result As String
Dim tempFile As String
Dim xmlDoc As Object ' MSXML2.DOMDocument
Dim xmlDocRoot As Object ' MSXML2.IXMLDOMNode
Dim word As Object ' MSXML2.IXMLDOMNodeList
Dim wordstring As Object ' MSXML2.IXMLDOMNode
' length must be between 6 and 15 chars
If wordLength > 0 Then
If wordLength < 6 Or wordLength > 15 Then
MsgBox "length must be between 6 and 15 characters."
Exit Function
End If
End If
tempFile = Environ("temp") & "\random_wordnik_word.xml"
Set xml = GetMSXML
xml.Open "GET", "http://api.wordnik.com/api/words.xml/randomWord?length=" & wordLength, False
xml.setRequestHeader "api_key", apiKey
xml.setRequestHeader "hasDictionaryDef", hasDictionaryDef
xml.send
result = xml.responseText
' create XML file from result
Call CreateFile(tempFile, result)
Set xmlDoc = GetDomDoc
With xmlDoc
.async = False
.validateOnParse = False
.Load tempFile
End With
' check that the XML doc loaded
If LoadError(xmlDoc) Then
Exit Function
End If
' get root node
Set xmlDocRoot = GetRootNode(xmlDoc)
' get first level child nodes
Set word = GetChildNodes(xmlDocRoot)
GetRandomWord = word.Item(1).nodeTypedValue
End FunctionBy default, only words with dictionary definitions are returned.
We could also rewrite the function to get a new word if the previous word is more than X hours old (or any interval we want), by writing the date into the filename (as we did with the GetWordOfTheDay function) then parsing the filename for the date/time and comparing it with the current date/time.
Sample usage
Sub TestRandomWord() Dim apiKey As String apiKey = "your API key here" Debug.Print GetRandomWord(apiKey) ProgramExit: Exit Sub ErrorHandler: MsgBox Err.Number & " - " & Err.Description Resume ProgramExit End Sub
The Get Bi-Gram Function
Bigrams are two-word phrases that commonly appear together in English. This function will return the common bigrams for a given word.
Function GetBiGrams(apiKey As String, word As String, Optional numberOfResults As Long = 5) As String()
Dim xml As MSXML2.XMLHTTP
Dim result As String
Dim tempFile As String
Dim tempString() As String
Dim xmlDoc As MSXML2.DOMDocument
Dim xmlDocRoot As MSXML2.IXMLDOMNode
Dim bigrams As MSXML2.IXMLDOMNodeList
Dim bigram As MSXML2.IXMLDOMNode
Dim i As Long, j As Long
tempFile = environ("temp") & "\bigram" & word & ".xml"
' requery website if file doesn't exist
If Len(Dir(tempFile)) = 0 Then
Set xml = GetMSXML
xml.Open "GET", "http://api.wordnik.com/api/word.xml/" & word & "/phrases", False
xml.setRequestHeader "api_key", apiKey
xml.setRequestHeader "limit", numberOfResults
xml.Send
result = xml.responseText
' create XML file from result
Call CreateFile(tempFile, result)
End If
' open XML file
Set xmlDoc = GetDomDoc
With xmlDoc
.async = False
.validateOnParse = False
.Load tempFile
End With
' check that the XML doc loaded
If LoadError(xmlDoc) Then
Exit Function
End If
' get root node
Set xmlDocRoot = GetRootNode(xmlDoc)
' get first level child nodes
Set bigrams = GetChildNodes(xmlDocRoot)
' resize array, bi-grams have two fields (hence the prefix)
ReDim tempString(1 To bigrams.Length, 1 To 2)
For i = 1 To bigrams.Length
Set bigram = bigrams.item(i - 1)
For j = 1 To UBound(tempString, 2)
tempString(i, j) = bigram.childNodes(j + 1).nodeTypedValue
Next j
Next i
GetBiGrams = tempString
End FunctionSample usage
Sub TestGetBiGrams()
Dim apiKey As String
Dim word As String
Dim tempString() As String
Dim i As Long, j As Long
apiKey = "your API key here"
word = "blather"
tempString = GetBiGrams(apiKey, word)
For i = 1 To UBound(tempString)
For j = 1 To UBound(tempString, 2)
Debug.Print tempString(i, j)
Next j
Next i
ProgramExit:
Exit Sub
ErrorHandler:
MsgBox Err.number & " - " & Err.Description
Resume ProgramExit
End SubGetPartOfSpeech and GetWordType are used to translate the Enum sections into Strings. Use the ClearCache function to delete the accumulated XML files from the local temp directory as needed.
Function GetPartOfSpeech(partOfSpeech As partOfSpeech) As String
Select Case partOfSpeech
Case 0
GetPartOfSpeech = "noun"
Case 1
GetPartOfSpeech = "verb"
Case 2
GetPartOfSpeech = "adjective"
Case 3
GetPartOfSpeech = "adverb"
Case 4
GetPartOfSpeech = "idiom"
Case 5
GetPartOfSpeech = "article"
Case 6
GetPartOfSpeech = "abbreviation"
Case 7
GetPartOfSpeech = "preposition"
Case 8
GetPartOfSpeech = "prefix"
Case 9
GetPartOfSpeech = "interjection"
Case 10
GetPartOfSpeech = "suffix"
End Select
End Function
Function GetWordType(wordType As wordType) As String
Select Case wordType
Case 0
GetWordType = "synonym"
Case 1
GetWordType = "antonym"
Case 2
GetWordType = "form"
Case 3
GetWordType = "equivalent"
Case 4
GetWordType = "hyponym"
Case 5
GetWordType = "variant"
End Select
End FunctionSample Application Using Wordnik API
The following Word 2003 application uses the Wordnik API to produce definitions for highlighted words. It was my first Word add-in effort. Note that it was written in Word 2003 and won't work in 2007 or 2010.
Once placed into your Startup folder, it adds a submenu to your Tools menu with several options. To find out where your Startup folder is, go to Tools » Options » File Locations tab and look for the "Startup" entry.

If at any time you do not select a word before choosing any of the menu options, you get the following error message:

The Options
Check Current Word
This option merely verifies that the highlighted word is in the Wordnik dictionary.

Get Wordnik Definition
Choosing this option will prompt you for the part of speech you want:

When you select one, you are shown the appropriate definition.

Get Related Words
This menu option will return any synonyms of the currently selected word. If there are none (according to Wordnik), you will see this dialog:

Insert Definition
You can insert definitions directly into the active Document. After highlighting a word, choose "Insert Definition" and you'll be prompted as follows:

Click "Insert Definition" and you'll see the part of speech dialog box. After choosing the part of speech you want to return, the highlighted word is replaced with its definition (if it exists for that part of speech).
The next two menu options should be obvious: "Clear Word Cache" deletes all the .xml files in the local temp folder, and "About Wordnik For Word" is a typical About dialog.
How It Works
I had to learn how to code a Word add-in from scratch. There isn't much help available online. Almost everything I found was about writing COM add-ins using VSTO or some other platform.
After extensive browsing, I learned that the Word equivalent for Outlook's Application_Startup and Excel's Workbook_Open are AutoExec and AutoOpen. They both run at different times, but this MS KB article explains how to tell when each one fires.
The strange thing about both procedures is that they don't go into a class module. They can be placed anywhere in a standard module.
I simply duplicated the startup code in both AutoExec and AutoOpen because under usual circumstances (based on the KB article), only one will fire, so I wasn't concerned about duplicate code.
The AutoOpen/AutoExec macros
Using a global constant called APP_NAME, we first check if the Wordnik menu exists on the Tools menu.
Dim wordnikMenu As Office.CommandBarPopup Set mcb = Application.CommandBars.FindControl(ID:=30007) On Error Resume Next Set wordnikMenu = mcb.Controls(JPWDvbp.APP_NAME) wordnikMenu.Delete On Error GoTo 0
I use a constant for the app name, so we can easily change the name of the app (for example, to add a version number) and the change will cascade throughout the application.
To add the submenu to the Tools menu, I use the following code:
Set wordnikMenu = mcb.Controls.Add(msoControlPopup) wordnikMenu.Caption = "Wordnik &For Word"
Now we add each menu item in the order we want them to appear on the Wordnik menu.
Dim newButton As Office.CommandBarControl Set newButton = wordnikMenu.Controls.Add(Type:=msoControlButton) With newButton .Caption = "Check &Current Word" .OnAction = "GetCurrentWord" .FaceId = 837 End With
The Caption Property sets the display text for the control. Use the ampersand (&) to indicate the accelerator key.
The OnAction Property indicates the procedure to be run when the menu item is clicked.
To get the Face ID number, I use the excellent JMT Excel Utilities add-in for Excel.
To put a line between Insert Definition and Clear Word Cache, use ".BeginGroup = True".
The AutoClose procedure in Word is used for shutdown code. In this case, it deletes the Wordnik menu entry. All of the submenu items (Get Current Word, etc) disappear on their own.
Dim mcb As Office.CommandBarControl Dim wordnikMenu As Office.CommandBarControl ' delete menu entry Set mcb = Application.CommandBars.FindControl(ID:=30007) On Error Resume Next Set wordnikMenu = mcb.Controls(JPWDvbp.APP_NAME) wordnikMenu.Delete On Error GoTo 0
Get Current Word
The function GetWord returns the current word. All we need to do is call the function and check the return value. The function does all the work for us.
For all you aspiring Word VBA programmers, ActiveDocument.ActiveWindow.Selection.Text returns the currently highlighted text.
Sub GetCurrentWord()
On Error GoTo ErrorHandler
Dim currentSelection As String
If Documents.Count > 0 Then
currentSelection = Trim(Replace(ActiveDocument.ActiveWindow.Selection.Text, Chr(13), ""))
If Len(currentSelection) < 2 Then
MsgBox NOTHING_SELECTED, , JPWDvbp.APP_NAME
Exit Sub
End If
If GetWord(currentSelection, apiKey) = currentSelection Then
MsgBox "'" & currentSelection & "' is found in the Wordnik dictionary.", vbInformation, JPWDvbp.APP_NAME
Else
MsgBox "Cannot locate this word in the Wordnik dictionary", vbCritical, JPWDvbp.APP_NAME
End If
End If
ProgramExit:
Exit Sub
ErrorHandler:
MsgBox "Sorry, an error occurred. Please try again."
Resume ProgramExit
End SubThe error handler merely displays a simple error message, rather than an error code. To is to avoid confusing the end user.
Get Current Word Definition
This procedure simply calls the GetDefinition function and parses the result. First it opens a userform that requests the part of speech. I chose to only return three possible parts of speech — nouns, verbs and adjectives.
In order to check the return value of the userform, we instantiate it as an object. Depending on which option button is selected, we set our partOfSpeech variable to the appropriate value and then pass it to the GetDefinition function so it knows which part of speech to pull from the web.
Sub GetWordDefinition()
On Error GoTo ErrorHandler
Dim currentSelection As String
Dim frm As JPWDvbp.WordnikPartOfSpeech
Dim pos As partOfSpeech
Dim definition As String
If Documents.Count > 0 Then
currentSelection = Trim(Replace(ActiveDocument.ActiveWindow.Selection.Text, Chr(13), ""))
If Len(currentSelection) < 2 Then
MsgBox NOTHING_SELECTED, , JPWDvbp.APP_NAME
Exit Sub
End If
Set frm = New JPWDvbp.WordnikPartOfSpeech
frm.Show
Select Case True
Case frm.optAdjective
pos = adjective
Case frm.optNoun
pos = noun
Case frm.optVerb
pos = Verb
Case Else
MsgBox "You must choose a part of speech to return the appropriate definition.", vbInformation, JPWDvbp.APP_NAME
Exit Sub
End Select
' return correct definition
definition = GetDefinition(currentSelection, apiKey, pos)
If Len(definition) > 0 Then
MsgBox definition, vbInformation, JPWDvbp.APP_NAME & " - Definition"
Else
MsgBox "No definition found for this word.", , JPWDvbp.APP_NAME
End If
End If
ProgramExit:
Exit Sub
ErrorHandler:
MsgBox "Sorry, an error occurred. Please try again."
Resume ProgramExit
End SubThe other functions work similarly. They call the appropriate function and parse the result or compare it with an empty string.
The Part of Speech Form

All of the option buttons on the part of speech form have one line of code:
Unload Me
The form is called by two procedures (outside the class module), and each one instantiates the form as an Object. In this way, we can check the value of each option button after the form closes!
The Insert Definition Form

This form does a couple of things:
- Automatically picks up currently highlighted word in current document
- Checks the spelling of current word
To pick up the currently selected word, we use the following code:
currentSelection = Trim(Replace(ActiveDocument.ActiveWindow.Selection.Text, Chr(13), "")) Set frm = New JPWDvbp.WordnikForm With frm .WordTextBox.Value = currentSelection .Show End With
The About Form
This form has two labels that are formatted to look like hyperlinks. They work like hyperlinks too. When you double click them, they open up the default web browser and visit either this site, or Wordnik's website. The DblClick Event handles this for us.
Private Sub WORDNIK_DblClick(ByVal Cancel As MSForms.ReturnBoolean) On Error GoTo ErrorHandler System.Cursor = wdCursorWait ThisDocument.FollowHyperlink "http://www.wordnik.com/" System.Cursor = wdCursorNormal ProgramExit: Exit Sub ErrorHandler: MsgBox Err.Number & " - " & Err.Description Resume ProgramExit End Sub
