Solved

Change Word Field Types in Documents

Posted on 2013-12-18
15
885 Views
Last Modified: 2014-01-03
Microsoft Word VBA Code /macro needed

I'd like to loop thru Word documents in a directory, open each document and change each Word field's type (WdFieldType) in each document to a "Mergefield" type.

This is what fields are in a sample doc now as an example:


Here is the macro I wrote to tell what the supposed Boookmarks really were:

Sub IdentifyFields()

Dim f As Word.Field
Dim b As Word.Bookmark

For Each f In ActiveDocument.Fields
    Debug.Print ("Field Index: " & f.Index & " Field Code: " & f.Code & " Type: " & f.Type & " Kind: " & f.Kind & " ")
Next f

End Sub
Here is the result (The only bookmark was the one I added as a test):

Field Index: 1 Field Code:  OrdClosingDate_1_14_0  Type: 3 Kind: 2
Field Index: 2 Field Code:  OrdDPSell1.1_1_0_0  Type: -1 Kind: 0
Field Index: 3 Field Code:  SellVestTxt_2_0_2  Type: 3 Kind: 2
Field Index: 4 Field Code:  GrantorAddress_1_0_0  Type: 3 Kind: 2
Field Index: 5 Field Code:  SellNameFL_23_0_2  Type: 3 Kind: 2
Field Index: 6 Field Code:  SellNameFL_26_0_2  Type: 3 Kind: 2
Field Index: 7 Field Code:  OrdDPBuy1.1_1_0_0  Type: -1 Kind: 0
Field Index: 8 Field Code:  GranteeAddress_1_0_0  Type: 3 Kind: 2
Field Index: 9 Field Code:  BuyNameFL_24_0_2  Type: 3 Kind: 2
Field Index: 10 Field Code:  BuyNameFL_29_0_2  Type: 3 Kind: 2
Field Index: 11 Field Code:  OrdSalesPrice_1_1_0  Type: 3 Kind: 2
Field Index: 12 Field Code:  OrdSalesPrice_2_0_0  Type: 3 Kind: 2
Field Index: 13 Field Code:  SellNameFL_31_0_2  Type: 3 Kind: 2
Field Index: 14 Field Code:  SellNameFL_32_0_2  Type: 3 Kind: 2
Field Index: 15 Field Code:  OrdDPBuy1.1_2_0_0  Type: -1 Kind: 0
Field Index: 16 Field Code:  OtherTenancyLang_1_0_0  Type: 3 Kind: 2
Field Index: 17 Field Code:  DoYouWantLots_1_0_0  Type: 3 Kind: 2
Field Index: 18 Field Code:  OrdPrimCntyName_3_0_0  Type: 3 Kind: 2
Field Index: 19 Field Code:  Legal_1_0_0  Type: 3 Kind: 2
Field Index: 20 Field Code:  HomesteadLanguageY/N_1_0_0  Type: -1 Kind: 0
Field Index: 21 Field Code:  HomesteadLanguageY/N_2_0_0  Type: -1 Kind: 0
Field Index: 22 Field Code:  OwnerOccLangSoleY/N_2_0_0  Type: -1 Kind: 0
Field Index: 23 Field Code:  OwnerOccLang2MoreBwrrsY/N_2_0_0  Type: -1 Kind: 0
0
Comment
Question by:swendell
  • 10
  • 5
15 Comments
 
LVL 76

Expert Comment

by:GrahamSkan
Comment Utility
At first glance, there seem to be a number of problems with what you are trying to do.

Firstly, a merge field needs to be of the general format

{ MERGEFIELD fieldname } where fieldname refers to a field name in a specified data source

Secondly, only Form Fields can have a bookmark to define their positions in a document, so the question is quite confusing
0
 

Author Comment

by:swendell
Comment Utility
Here are the advanced field properties for one specific MERGEFIELD field code I wish to convert TO:
MERGEFIELD  RESWARE_SP_GetBuyerSellerCityStateZip_Buyer_1

Above you can see the debug.print of some fields and their .FieldTypes I am converting FROM.

So for the first one; I would like the field changed to be:
MERGEFIELD OrdClosingDate_1_14_0
It will work if I change the type to MERGEFIELD, a 3ed party module interprets and replaces these Word MergeFields.

Maybe cut the current Word Field while saving Word.Field.code then .add a new MergeField in the position with the saved Word.Field.code ?
0
 

Author Comment

by:swendell
Comment Utility
One step closer,
This code successfully found and replaced the first field with a mergefield
Unfortunately it did not move onto the next field in the loop to continue replacing the remaining fields in the document, but a great start

Dim f As Word.Field
Dim MyRange As Object

For Each f In ActiveDocument.Fields
     Debug.Print ("Field Index: " & f.Index & " Field Code: " & f.Code & " Type: " & f.Type & " Kind: " & f.Kind & " ")
     
f.Select

Selection.Fields.Add Range:=Selection.Range, Type:=wdFieldEmpty, Text:= _
        "MERGEFIELD OrdClosingDate_1_14_0", PreserveFormatting:=False
Selection.MoveLeft Unit:=wdCharacter, Count:=1, Extend:=wdExtend

Next f

End Sub
0
 
LVL 76

Expert Comment

by:GrahamSkan
Comment Utility
Sorry. I thought that I posted some code last night. The way round that problem  is to use indexing instead of For Each. Modifying the field modifies the Fields collection, so the Next doesn't work. This is what I wrote last night:
Sub ChangeToMergeFields()
    Dim fld As Field
    Dim rng As Range
    Dim strWords() As String
    Dim strText As String
    
    Dim w As Integer
    Dim f As Integer
    
    For f = 1 To ActiveDocument.Fields.Count
        Set fld.Kind = ActiveDocument.Fields(f)
        Set rng = fld.Code
        strText = rng.Text
        strWords = Split(strText, " ")
        For w = 0 To UBound(strWords)
            If Len(Trim(strWords(w))) > 0 Then
                strWords(w) = "MERGEFIELD"
                Exit For
            End If
        Next w
        strText = Join(strWords, " ")
        fld.Delete
        ActiveDocument.Fields.Add rng, wdFieldEmpty, strText
    Next f
End Sub

Open in new window

0
 

Author Comment

by:swendell
Comment Utility
Error: Invalid use of property - KIND
Set fld.Kind = ActiveDocument.Fields(f)
0
 
LVL 76

Expert Comment

by:GrahamSkan
Comment Utility
Yes that is not surprising.

I have no idea where that came from. The code worked 24 hours ago. It is trying to set a field property to the field object itself.

It should be:
Set fld = ActiveDocument.Fields(f)
0
 

Author Comment

by:swendell
Comment Utility
It is inserting Mergefields without a field name where the old fields were. That is GREAT; Now we need to save the old field name then use it when adding this new MERGEFIELD so the MERGEFIELD name will not be empty  

It should look like: {MERGEFIELD OrdClosingDate_1_14_0}
Now it looks empty like this:  { MERGEFIELD \* MERGEFORMAT}
0
Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

 

Author Comment

by:swendell
Comment Utility
Maybe I should have attached this to begin with....
FM000391.doc
0
 
LVL 76

Expert Comment

by:GrahamSkan
Comment Utility
That certainly helps.

None of the fields in your document have a field type name in them. This makes them, by default, REF fields. REF fields display the text of the given bookmark name (the first word in the field, or the second if it us "REF").

When I said 'last night',  it was really so. I'm on GMT, so it's nearly midnight here. I'll try to get back in about eight hours' time
0
 

Author Comment

by:swendell
Comment Utility
Thank you so much!!!!!!!!!!!
I was able to get the field name/code in my originally posted example so I guess you know what to do. The last piece is a loop that will:
- loop thru a directory of the docs to be converted. For example: C:\Input
- save each converted document with same name to a folder like C:\Output
0
 
LVL 76

Accepted Solution

by:
GrahamSkan earned 500 total points
Comment Utility
Here is some code to loop through a folder and to save the modified document.
Some tweaks were necessary to the original procedure, so that is also here.
Sub ProcessFiles()
    Dim strFile As String
    Dim strInFolder As String
    Dim strOutFolder As String
    Dim doc As Document
    
    strInFolder = "C:\Input"
    strOutFolder = "C:\Output"
    
    strFile = Dir$(strInFolder & "\*.doc*")
    Do Until strFile = ""
        Set doc = Documents.Open(strInFolder & "\" & strFile)
        ChangeToMergeFields doc
        doc.SaveAs strFile & "\" & strOutFolder
        doc.Close
        strFile = Dir$()
    Loop
End Sub


Sub ChangeToMergeFields(doc As Document)
    Dim fld As Field
    Dim rng As Range
    Dim strWords() As String
    Dim strText As String
    
    Dim w As Integer
    Dim f As Integer
    
    For f = 1 To doc.Fields.Count
        Set fld = doc.Fields(f)
        Set rng = fld.Code
        strText = rng.Text
        strWords = Split(strText, " ")
        For w = 0 To UBound(strWords)
            If Len(Trim(strWords(w))) > 0 Then
                strWords(w) = "MERGEFIELD"
                Exit For
            End If
        Next w
        strText = Join(strWords, " ")
        fld.Delete
        doc.Fields.Add rng, wdFieldEmpty, strText
    Next f
End Sub

Open in new window

0
 

Author Comment

by:swendell
Comment Utility
I am driving for the next day or two but will test it when I stop, thank you so much for all the help, I'd like to send you a gift of appreciation like an amazon gift card not just points,  just don't know where to send it...
0
 

Author Comment

by:swendell
Comment Utility
Just at a glance I reversed the output file path but I do not think the new Mergefields have any field names...
0
 

Author Comment

by:swendell
Comment Utility
OK , I fixed the output path and added Mergefield name, It 'seems' OK, but I will need to test to confirm:

Sub ProcessFiles()
    Dim strFile As String
    Dim strInFolder As String
    Dim strOutFolder As String
    Dim doc As Document
    
    strInFolder = "C:\AIMInput"
    strOutFolder = "C:\AIMOutput"
    
    strFile = Dir$(strInFolder & "\*.doc*")
    Do Until strFile = ""
        Set doc = Documents.Open(strInFolder & "\" & strFile)
        ChangeToMergeFields doc
        doc.SaveAs strOutFolder & "\" & strFile
        doc.Close
        strFile = Dir$()
    Loop
End Sub


Sub ChangeToMergeFields(doc As Document)
    Dim fld As Field
    Dim fldsave As String ' this is the field to store te old field name before we replce it
    
    Dim rng As Range
    Dim strWords() As String
    Dim strText As String
    
    Dim w As Integer
    Dim f As Integer
    
    For f = 1 To doc.Fields.Count
        Set fld = doc.Fields(f)
        Set rng = fld.Code
        fldsave = rng.Text
        strText = rng.Text
        strWords = Split(strText, " ")
        For w = 0 To UBound(strWords)
            If Len(Trim(strWords(w))) > 0 Then
                strWords(w) = "MERGEFIELD" & " " & fldsave ' added missing Mergefield name
                Exit For
            End If
        Next w
        strText = Join(strWords, " ")
        fld.Delete
        doc.Fields.Add rng, wdFieldEmpty, strText
    Next f
End Sub

Open in new window

0
 

Author Closing Comment

by:swendell
Comment Utility
Sorry I took so long to test over the holiday but you got the essence of it very well
0

Featured Post

Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

Join & Write a Comment

This is an explanation of a simple data model to help parse a JSON feed
Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
This video shows and describes the main difference between both orientations in Microsoft Word. Viewers will understand when to use each orientation and how to get the most out of them.
In a previous video Micro Tutorial here at Experts Exchange (http://www.experts-exchange.com/videos/1358/How-to-get-a-free-trial-of-Office-365-with-the-Office-2016-desktop-applications.html), I explained how to get a free, one-month trial of Office …

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

7 Experts available now in Live!

Get 1:1 Help Now