how to access the heading REF ID of a heading in Word via VBA/Perl?


I'm trying to write a parser in Perl to parse a Microsoft Word document. I'm trying to find out how to retrieve the REF Id of headings or captions in my document but have had no success. I can get access to the REF Id from cross references to these headings and captions. But this gets me half way there. I also need to know where these REF Id live in the document - namely the heading and caption locations to complete the link. Here's how I access the REF Id from the cross reference in the document:

my $fieldsCollection = $document->Fields();
$enumerate = new Win32::OLE::Enum($fieldsCollection);
while(defined(my $field = $enumerate->Next())) {
    if ($field->Type == wdFieldRef) {
        # a cross-reference
        if ($field->Code->Text =~ /REF _Ref/) {
            my $fieldCode = $field->Code->Text;
            my $fieldText = $field->Result->Text;
            my $startAt = $field->Result->Start;
            my $endAt = $field->Result->End;
            &logMsg(TRC_DEBUG, "$fieldCode, $fieldText, $startAt, $endAt");

I can lookup the list of styles, headings, bookmarks, fieldcode and paragraph objects defined in the document but cannot see how i can get access to this REF Id from Word's Object Model.

Hoping someone can help.
Who is Participating?
GrahamSkanConnect With a Mentor RetiredCommented:
Well I am surprised. It seems that the collection does not show hidden bookmarks in the count, and so they cannot be returned by index number, but a hidden bookmark can be found by name.

I have just created a document with a numbered heading and inserted a cross-reference field to it. I ran the VBA macro code below to demonstrate that effect.
Sub FindXReference()
    Dim fld As Field
    Dim strFieldText As String
    Dim strBookMarkName As String
    Dim strReferencedText As String
    Dim strWords() As String
    Dim i As Integer
    Dim bmk As Bookmark
    MsgBox "BookMark Count:" & ActiveDocument.Bookmarks.Count 'returns 0 
    For Each bmk In ActiveDocument.Bookmarks
        MsgBox "Bookmark: " & bmk.Name & ", " & bmk.Range.Text 'No message displayes
    Next bmk
    For Each fld In ActiveDocument.Fields
        If fld.Type = wdFieldRef Then
            Set fld = ActiveDocument.Fields(1) 'only the one field in my test document
            strFieldText = fld.Code
            MsgBox "Field code: " & strFieldText
            strWords = Split(strFieldText, " ")
            'REF is the default field feidl type so that the word REF sould be omitted
            For i = 0 To UBound(strWords)
                If Left$(strWords(i), 4) = "_Ref" Then 'Hidden bookmark in XRef format
                    strBookMarkName = strWords(i)
                    Exit For
                End If
            Next i
            MsgBox "Bookmark: " & strBookMarkName
            strReferencedText = ActiveDocument.Bookmarks(strBookMarkName).Range.Text
            MsgBox "Referenced Text: " & strReferencedText
        End If
    Next fld
End Sub

Open in new window

That's the first Perl code that I have seen, so I won't try to give you a code sample.

The REF Id is a hidden Bookmark. It is created automatically when the user inserts a cross reference. Hidden bookmark names begin with an underscore and are not normally shown in the Bookmarks dialogue.

Bookmarks have a range. In the case of a numbered paragraph (heading) the bookmark's range includes the whole of the paragraph text.
tricassAuthor Commented:
Hi GrahamSkan,

Thanks for clue. I thought it might have been a bookmark but when I retrieve the lists of Bookmarks from the document I get an empty collection. Sorry about the Perl code :). However, if you don't mind providing an example in VB code I might be able to translate into a Perl equivalent. In fact, that's how I got started with this parsing work as most of the material on the web uses VB. Here's the Perl equivalent I used to retrieve the list of Bookmarks.

my $bookmarksCollection = $document->Bookmarks();
$enumerate = new Win32::OLE::Enum($bookmarksCollection);
while(defined(my $bookmark = $enumerate->Next())) {
    my $bookmarkName = $bookmark->Name;
    my $bookmarkStart = $bookmark->Start;
    my $bookmarkEnd = $bookmark->End;
    my $startAt = $bookmark->Range->Start;
    my $endAt = $bookmark->Range->End;
    &logMsg(TRC_DEBUG, "$bookmarkName, $bookmarkStart, $bookmarkEnd, $startAt, $endAt");

Looking at the Word Object Model Reference information I could not find a method that would allow me to search for a matching bookmark based on the _Ref code defined in a cross reference.

Get expert help—faster!

Need expert help—fast? Use the Help Bell for personalized assistance getting answers to your important questions.

tricassAuthor Commented:
Exactly what I was after. Thanks!

I have to say the documentation at ( does not indicate you can use the Bookmarks method in such a manner! I guess its an undocumented feature :)
I thought that I had already set the option to show hidden bookmarks in the dialogue, so I didn't mention it as it seemed to be ineffective. However that option does make the hidden bookmarks fully visible programatically.

You can set it in code:

    ActiveDocument.Bookmarks.ShowHidden = True

tricassAuthor Commented:
Just tested it and it works! So I now have two approaches to chose from.

Thanks for the follow-up.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.