PDA

View Full Version : Hyperlinking Indexes



Anne Troy
08-24-2004, 09:52 PM
It appears that some tech writers at http://www.raycomm.com/techwhirl/archives/0404/techwhirl-0404-00739.html

would love to have a method to hyperlink indexes that are created in Word.

I found that thread because someone over at Tek-tips is asking for this feature...

Can we do it?

JOrzech
08-26-2004, 04:02 PM
What about this?

http://word.mvps.org/FAQs/Numbering/Createindex.htm

Anne Troy
08-26-2004, 04:06 PM
Those don't hyperlink...

JOrzech
08-26-2004, 05:16 PM
It does refer how to hyperlink indexes....or have I totally lost it? :bink:



For the truly adventurous...

Technical writers and other folk who publish seriously-huge documents in HTML may want to spend a little time learning about Concordance Indexes. In conjunction with VBA, a concordance index is a great way to automatically generate hyperlinks in your document. You tag every mention of each term with the concordance indexing mechanism, then use VBA to change the tags into hyperlink tags.

Kelly
08-29-2004, 07:50 PM
Can we do it?
Most certainly we can do it!

I have been working with fields in Word quite a lot lately, so when I saw this thread I figured I must have what it takes by now to tackle something like this. (In case the connection between fields and indexes isn't immediately clear: indexes are created in Word through the use of fields)

At first glance, I was thinking that we basically have two options as to how to approach this.

We could let Word create the index automatically, and then we could unlink the "INDEX" field (thereby converting it to text) and play around with the pre-created index.
We could use the XE fields (the fields that are inserted to mark index entries, either manually or with Alt+Shift+X and the "Mark Index Entry" dialog) and basically design and generate our own index in whatever format we want, including hyperlinks as we do so.
After some thought, I decided that option #2 is probably the best. If we were to use option #1 and work with a pre-created index, we would have a very difficult time of extracting the information we need because there are so many possible formats that Word uses to create the indexes ("Classic," "Fancy," "Modern," etc). So there would be a lot of code for trudging through the text looking for what we want to link. Also, the user might be confused about how the index used to be a field that you could click on and update and now it is suddenly text.

So, in order to accomplish the "hyperlinked index" using my option #2, the user would first need to mark index entries in the document by whatever method they would normally use. Then you could run a macro that would find and store a list of all the marked entries and their locations in the document. Then the macro would also take that information and use it to draw up an index. The index created could even look just like an index created by Word, only it wouldn't be a field, and it WOULD be hyperlinked. If the document changes and the marked entries throughout the document change (some deleted, some added, etc), then you would only need to run the macro again to "update" the index (basically recreate it, but it would be the same result as an update).

Side comment:
The quote that JOrzech has included about hyperlinking and VBA is a little bit misleading. It's only misleading in the following way: it gives the impression that you can only hyperlink items tagged using the "Concordance" method. That's not true. You can just as easily find and hyperlink items marked in any old way. I think the quote about the "Concordance" thing is directed at people that want to make a web page in Word and they have a list or words such that every instance of the word (it could be a Company Name, or anything) should link to one same location. For example, every instance of "JOrzech" found on the page or document should hyperlink to JOrzech's homepage.
But that's not what we want to do for an index. The way I see it, we want the PAGE NUMBERS displayed in the index to hyperlink to that page and, moreover, to link straight to the position of the indexed word contained in that page.

So, as proof positive that this can be done (and as proof positive that I'm a glutton for punishment), I have written a macro that will do it.

If anyone out there has a document with XE fields (marked index entries), please feel free to test this macro and share the results with me.

At this point, the macro creates an index in the form of a table. It's not very attractive at all, but it is hyperlinked.

At a later date, I can most certainly modify the macro so that the index created will actually look like an attractive index similar to any index in the back of a published book.

Also, I'm sure there are MANY other members of VBAX that could modify it also. I wrote it as basically two separate procedures, one to collect data and the other to format the data into an index. That way, ideally, only the second procedure needs to be modified.

Sub Create_Hyperlinked_Index()

Dim possibleXE_field As Field
Dim TheCodeText As String 'the contents of the actual FIELD CODE, as opposed to its "result"
Dim Char4 As Integer 'the fourth character in the code must be a quotation mark!!!!
Dim FieldEndingText As String 'everything in the FIELD CODE that FOLLOWS the first quotation mark
Dim myCharPos As Integer 'a variable I use to try and find the location of the second quotation mark
Dim NumOfField As Integer 'this is a counter variable that keeps track of how many XE fields are found
Dim myEntry() As String 'an array to hold each ENTRY (the actual words for inclusion in the index)
Dim onPage() As String 'an array to hold the page number of each ENTRY
Dim atBookmark() As String 'an array to hold the name of the bookmark that marks the entry's location
Dim ErrorText As String 'useful error information to display if the user has "bad" XE fields
Dim FinishedMessage As String 'a message displayed upon completion advising the user that an index was created

Application.ScreenUpdating = False

For Each possibleXE_field In ActiveDocument.Fields

'BECAUSE THE LOOP FINDS ALL TYPES OF FIELDS, THE FIRST THING IS TO CHECK IF IT'S A INDEXENTRY FIELD
If possibleXE_field.Type = wdFieldIndexEntry Then

TheCodeText = Trim(possibleXE_field.Code.Text)
Char4 = Asc(Mid(TheCodeText, 4, 1))

'CHECK FOR THE LETTERS "XE" FOLLOWED BY A SPACE, FOLLOWED BY A QUOTATION MARK
If (StrComp("xe ", Left(TheCodeText, 3), vbTextCompare) = 0) And (Char4 = 147 Or Char4 = 148 Or Char4 = 34) Then

FieldEndingText = Mid(TheCodeText, 5)
myCharPos = 32767

If InStr(1, FieldEndingText, Chr(34), vbTextCompare) > 0 Then myCharPos = InStr(1, FieldEndingText, Chr(34), vbTextCompare)
If InStr(1, FieldEndingText, Chr(147), vbTextCompare) > 0 And InStr(1, FieldEndingText, Chr(147), vbTextCompare) < myCharPos < myCharPos Then myCharPos = InStr(1, FieldEndingText, Chr(147), vbTextCompare)
If InStr(1, FieldEndingText, Chr(148), vbTextCompare) > 0 And InStr(1, FieldEndingText, Chr(148), vbTextCompare) < myCharPos Then myCharPos = InStr(1, FieldEndingText, Chr(148), vbTextCompare)

If myCharPos < 2 Or myCharPos = 32767 Then

'IF WE FOUND THE OPENING QUOTATION MARK BUT DIDN'T FIND ANY SUBSEQUENT CLOSE QUOTATION MARK, THEN...
ErrorText = ErrorText & MessagesForTheUser(possibleXE_field)

Else

'THE NEXT FEW LINES ARE WHAT WILL EXECUTE WHEN A PROPERLY FORMATTED XE FIELD IS FOUND:
ReDim Preserve myEntry(NumOfField)
myEntry(NumOfField) = Left(FieldEndingText, myCharPos - 1) 'Store the text for the index entry

ReDim Preserve onPage(NumOfField)
onPage(NumOfField) = possibleXE_field.Code.Information(wdActiveEndAdjustedPageNumber) 'Store the page number for the index entry

ReDim Preserve atBookmark(NumOfField)
atBookmark(NumOfField) = "a" & Replace(CDbl(VBA.Now), ".", "") & NumOfField 'Store the bookmark name that we will hyperlink the entry to

ActiveDocument.Bookmarks.Add atBookmark(NumOfField), possibleXE_field.Code

NumOfField = NumOfField + 1

End If

Else

'IF WE DIDN'T FIND THE LETTERS "XE" FOLLOWED BY A SPACE, FOLLOWED BY A QUOTATION MARK, THEN...
ErrorText = ErrorText & MessagesForTheUser(possibleXE_field)

End If

End If

Next possibleXE_field

Application.ScreenUpdating = True

'*********** CHECK TO SEE IF ANY USABLE XE FIELDS WERE FOUND ***************

If NumOfField = 0 Then

If ErrorText = "" Then
MsgBox "There are no XE fields from which to create an index"
Else
MsgBox "No index could be created because the data within your XE fields" & vbCr & _
"is not formatted correctly." & vbCr & vbCr & "Please fix the following " & _
"fields and try again:" & ErrorText
End If

End 'IF NO XE FIELDS WERE FOUND, THE PROCEDURE WILL END RIGHT HERE

End If

'******** CALL THE PROCEDURE THAT WILL CREATE THE INDEX USING myEntry, onPage, AND atBookmark *******

PutTheIndexInTheDoc myEntry, onPage, atBookmark

'********* DISPLAY FINAL INFORMATION TO THE USER *****************************************

FinishedMessage = "A hyperlinked index was created at the end of your document."

If ErrorText <> "" Then
FinishedMessage = FinishedMessage & vbCr & vbCr & "The following is a list of XE fields " & _
"that were NOT included in" & vbCr & "the index because their data does not " & _
"fit the format of ""{XE ""entry text"" optional switches}""" & ErrorText
End If
MsgBox FinishedMessage

End Sub
Function MessagesForTheUser(myField As Field)

Dim myCode As String
Dim myPage As String

myCode = "{" & myField.Code.Text & "}"

myPage = CStr(myField.Code.Information(wdActiveEndAdjustedPageNumber))

MessagesForTheUser = vbCr & vbCr & myCode & vbCr & vbTab & "(on page #" & myPage & ")"

End Function
Sub PutTheIndexInTheDoc(TheEntries() As String, ThePageNums() As String, TheBookmarks() As String)

Dim myTable As Table

Dim myPosition As Integer
Dim RangeOfBadCarriageReturn As Range

Dim x As Integer
Dim y As Integer

Application.ScreenUpdating = False

ActiveDocument.Characters(ActiveDocument.Characters.Count).InsertAfter vbCr & vbCr

Set myTable = ActiveDocument.Tables.Add(Range:=ActiveDocument.Characters(ActiveDocument.C haracters.Count), NumRows:=UBound(TheEntries) + 1, NumColumns:=2)

For x = 0 To UBound(TheEntries)

myTable.Columns(1).Cells(x + 1).Range.Text = TheEntries(x)
ActiveDocument.Hyperlinks.Add myTable.Columns(2).Cells(x + 1).Range, "", TheBookmarks(x), TheEntries(x), ThePageNums(x)

Next x

myTable.Sort ExcludeHeader:=False, FieldNumber:="Column 1", SortFieldType:=wdSortFieldAlphanumeric, SortOrder:=wdSortOrderAscending

y = 2
Do While y <= myTable.Rows.Count

If Trim(myTable.Columns(1).Cells(y).Range.Text) = Trim(myTable.Columns(1).Cells(y - 1).Range.Text) Then

myTable.Columns(2).Cells(y - 1).Merge myTable.Columns(2).Cells(y)

myPosition = InStr(1, myTable.Columns(2).Cells(y - 1).Range.Text, vbCr)
Set RangeOfBadCarriageReturn = myTable.Columns(2).Cells(y - 1).Range.Characters(myPosition)
RangeOfBadCarriageReturn.Text = ","

myTable.Columns(1).Cells(y).Delete wdDeleteCellsEntireRow

Else

y = y + 1

End If

Loop

Application.ScreenUpdating = True

End Sub

Anne Troy
08-29-2004, 08:00 PM
Side comment correct-o-mundo! :)
Thanks. I know I've got one somewhere, Kel. I'll do as soon as I can. Meanwhile, if anybody else has one...

Anne Troy
08-29-2004, 08:16 PM
Thanks to Starl, I'm testing!!

Anne Troy
08-29-2004, 08:23 PM
Wow! That was fast. And worked!
The only problem I see is this...

Many of the index entries read something like:

Graphics:Tables, using with

From what I can see, we just need to get a space after the colon, then it's a simple matter of converting the table to text, do a right-aligned tab, and format the section as 2-column.

Cool!

fumei
08-29-2004, 11:25 PM
Smart gal that Kelly. Kelly can you add that to the addin, and posy nack into that thread?

Kelly
09-29-2004, 10:51 PM
After more hours that I should probably admit to....
I have a revised version of my previous macro for creating hyperlinked indexes.

This version is still only a "skeleton" compared to the mental image that I am envisioning for my "final version," but the index made by this macro is far more "exciting looking" than the previous version.

You'll have to download the zipped file to view the code, because there is too much code to paste here and because the document as a whole should "come with" a reference to the VBScript Regex library (I hope). If you were to cut and paste my code from here, you would need to add the reference manually.

Also, the document comes with over 200 XE fields included!!! (that's important -- it would NOT be fun to create your own testing document for this macro)

NOTE: the document text is more or less gibberish. I created a "book" by cutting and pasting from essays I found on the Internet. Also, the Index Entries are pure fantasy also - most of them are names of wild animals.

If anyone has a "real" document with XE fields in it, please try testing the macro on your "real" document. I would be very interested to get feedback.

Kelly
11-07-2004, 09:59 PM
I'm back!

Here are some pictures (screen-shots) of a NEW version of the utility. I hope these pictures will ENTICE you to download my "indexer" and try it out.

Don't be shy about commenting. Or you could email me, either through this forum or at the email address shown at this link (http://members.dslextreme.com/users/kkj/images/me.gif).

Don't forget to SUBSCRIBE to this thread to receive further updates!

Kelly
11-07-2004, 10:02 PM
One more enticing picture and then I'll post the actual document.

Kelly
11-07-2004, 10:03 PM
Here it is... my latest toy!!

It actually has options now!!

johnske
11-07-2004, 10:50 PM
Another Tour De Force from Kelly... :cool

It works a treat, this is something I can USE!!! (I'm subscribing to this thread now to keep updated) :bink:

johnnyg248
05-15-2008, 08:09 AM
This may seem like a silly question but....

I downloaded the zip file and extracted the template file but not sure what to do with it

Paul_MUC
02-08-2011, 10:14 AM
This may seem like an even sillier question, but:
Does anyone have Kelly's zip file on hand? It sounds like just what I've been looking for, but it and the screenshots are no longer appearing in the posts above.

Thanks very much!