In my last post, I covered the overview of this project, and the stuff you need to know before you get started.
In this installment, we’re looking at taking a FileMaker Go app, and setting it up to record field edits into XML. There are two things we want to accomplish here:
- Only show the latest edit per field
- Make the XML look beautiful so that it’s easy to read, edit, and debug
As I said last time, you need to remind yourself often that this is not an audit log, where we record every little change the user makes. The only purpose for this project is to take the current data structure of a Filemaker Go solution and sync it with a central data system. In this case we have a contact management system in the wild, and a system back at the office that incorporates the wilderness contact information into a much larger solution.
As you might expect, we have some name/number/address fields in our contact solution. Here is the current information the Go user has currently:
Fields before editing
Let’s edit some fields and see what happens:
Fields after editing
Here is the XML that was built after exiting the layout:
XML generated after editing
Note the structure of the XML. First, we declare that we’re editing a Bank record, with the tag. Next, we move to the next line and indent to show that we’re adding information that belongs inside this bank record. I always declare the bank serial (or ID, if you use that terminology), to immediately identify which record we’re looking at.
Next, there is a list of fields that have been edited. Note that underneath each field is the Timestamp, also indented to show that it belongs only to the data directly above it. (I’m new to XML, so I’m confident that my structure here is a bit loose, but I think I have the right idea.) We will need this Timestamp in the main system so we can tell whether or not this is the latest edit for this field.
Finally, we have a tag letting us know that we’re to the end of edits for this particular bank.
Let’s investigate how this XML gets built.
Building The XML
For each field that I need to send back to the main system, I have a set of script triggers. The OnEnter script trigger is called “OnTimer Stop”. This script stops the currently running OnTimer script that’s checking for activity. If there is no activity for awhile, the system switches layouts to the log-in screen – a screen locking mechanism. To prevent the OnTimer from getting in the way of editing, I simply turn off the current one by installing an empty one, which is all this script does.
Whenever a field is saved, I record that information into a global variable via the OnSave Bank Fields script. This is one of the scripts we will look at in the next post.
OnExit, I re-install the screen lock OnTimer script.
When a bank is selected, we take a snapshot in XML of what the field values are, and store it in the variable $$CurrentBankValues. Let’s step through the script, and see how that works.
Here’s the script:
Script: Get Current Bank Values
In the section labeled, “Set a list of fields we want to collect information on,” we set a variable to list all of the field names we want to collect information about.
Enter your field names like this
For cross-platform safety, don’t formulate the calculation thusly:
Save yourself some trouble, and don't do it like this. Though the neatness is preferred, the hidden character troubles are not.
That extra invisible returns can sometimes confuse Windows. Don’t ask me why – all I remember is that I had to change from the vertical orientation (my preference) to the continuous version (yuck) because there were problems. And I couldn’t get the ascii character to filter out. If you have a solution, post it in the comments. But the safest practice is the run-on-sentence version of the calculation.
In a moment, we’ll be looping through this list of fields.
Next, we empty the global variable $$CurrentBankValues, because…well…we want to set the values of the current bank, not the bank we selected last time.
Now, we’re down to the start of the fun part: building the XML. Obviously, we need a header explaining what kind of record this is. So we set our recently-cleared-now-ready-for-new-data global variable $$CurrentBankValues to:
” <Bank>¶ <Serial>” & GetField ( Get ( LayoutTableName ) & “::zzk_Serial” ) & ” </Serial>”
Creating the header
That’s two spaces in front of the Bank tag, and four spaces in front of the serial tag. Yes, every time you create a new level, add two more spaces. It looks tidy, and it’s easy to remember: multiply the level by two.
(The reason I’m indenting the Bank tag is because I’m going to eventually wrap the whole thing with user and transactional timestamp tags, which will occupy the no-indention level.)
The result looks like this:
Next, we want to loop through all the fields we defined earlier, and set their current values (go figure!):
I use often the Exit Loop If function for defining values in addition to its native function. In this case, incrementing the counter used elsewhere in the script.
The first thing I do is use my Exit Loop If statement to define the loop counter. This way, I don’t have to have a separate Set Variable ( ) step for declaring the counter and incrementing it.
I then define the field that we should be paying attention to. The way that I do that is to take the MiddleValues of the list of BankFields we defined moments ago, select the value that corresponds to the $Count, grabbing only one value.
TrimMV is my custom function for getting rid of the return at the end of the data returned by MiddleValues. That custom function is simply:
Substitute ( Text ; “¶” ; “” )
So, if you don’t want to mess with custom functions (or can’t), you’ll need to write it all out:
Substitute ( MiddleValues ( Text ; $Count ; 1 ) ; “¶” ; “” )
Lastly, if there is no value for Field, we exit the loop, because that will mean we’ve run out of field names to process.
You could use the FieldNames ( ) function to create the list of field names to process for a given table. And this, of course, would update as field names changed. The problem here is that I don’t really want to track all the fields. Just the ones that the user interacts with. Therefore, I’m using a manually-created list.
The final part of building the initial XML values is adding the footer:
The resulting XML looks something like this:
<Consultant>Your Sales Consultant</Consultant>
<Notes>12/2/2011 4:21 PM Brad Stanford – Brad’s Test</Notes>
<LegalAddress>1234 One-Way Ave</LegalAddress>
<MailingAddress>1234 Your-Way Street</MailingAddress>
<ServiceType>BOLI & Benefits</ServiceType>
All we’ve done so far is click on a record, and create an XML snapshot of the current information in the fields we’re interested in. Next time, we’ll look at what happens to this XML when we edit a field.