Contents

Why XFDF?

XFDF (XML Forms Data Format) and it's older sibling, FDF, are file formats used to populate PDF forms with data.

The Adobe XML architecture combines the powerful data and business logic capabilities of XML with the rich presentation capabilities of Adobe® Portable Document Format (PDF).

XFDF provides a straight forward path to integrating Force.com data with the power of Adobe PDF and PDF forms.

A typical use case might be the need to populate a third party's form with data from a user record or a contact record stored in the Force.com database. Often the form is provided by a third party and cannot be modified. In these cases the data must be entered into the form to meet the requirements of the third party. Using Force.com data and a simple Visualforce page can quickly solve this type of lightweight integration.

Understanding Adobe XFDF

Adobe Spec

An Adobe XFDF file contains the filename and location of the PDF form from which the form data in that particular XFDF file was exported. Adobe Reader (and any PDF-viewing/editing application that supports PDF forms) relies on that filename and location in order to retrieve and open the appropriate PDF form when opening an XFDF file. In other words: when opening an XFDF file, a PDF viewing/editing application assumes that the PDF form from which the form data was exported is available at the specified location.

Therefore, you can use your Force.com platform as a reliable method of storing the required PDF forms in known locations. Otherwise, it will not always be possible for PDF-viewing/editing applications to retrieve and open the PDF Forms when they are needed. We will use a Sites enabled developer edition in this example.

Example Code

To cover the source code steps, first we will look at generating the XML containing our data, here is a simple method to generates the XFDF string given a Contact record.

Note we specify a form location on a public URL where we have stored an Adobe Form document. This example uses some custom fields, you can trim those out as needed by your form.

       private String getXmlString(Contact c)
        {
            String s = '<?xml version="1.0" encoding="UTF-8"?>' +
	            '<xfdf xmlns="http://ns.adobe.com/xfdf/" xml:space="preserve">' +
	            '<f href="http://mysites-developer-edition.na1.force.com/resource/0/myform.pdf"/>' +
	            '<fields>' +
	            '<field name="DOB"><value>' + c.birthdate + '</value></field>' +
	            '<field name="Name"><value>' + c.firstname + ' ' + c.lastname + '</value></field>' +
	            '<field name="SS"><value>' + c.SS_Number__c + '</value></field>' +
	            '<field name="Phone"><value>' + c.phone + '</value></field>' +
	            '<field name="Citizenship"><value>' + c.Citizenship__c + '</value></field>' +
	            '<field name="CountryOfBirth"><value>' + c.Country_of_Birth__c + '</value></field>' +
	            '<field name="Tax"><value>' + c.Country_of_Tax_Residence__c + '</value></field>' +
	            '<field name="GovId"><value>' + c.Government_Identification__c + '</value></field>' +
	            '<field name="IdNumber"><value>' + c.ID_Number__c + '</value></field>' +
	            '</fields><ids original="FEBDB19E0CD32274C16CE13DCF244AD2" modified="5BE74DD4F607B7409DC03D600E466E12"/>' +
	            '</xfdf>';
                        
            return s;
        }       
        


In the above example, the "ids" element’s "original" attribute contains a permanent identifier for the form and the "modified" attribute contains an identifier that changes with each modification to the file. You will need to determine the "original" and "modified" attributes for your form, as they will be different than those listed here. The instructions for doing so are here.

Also, when you upload the form to a static resource, be sure to set the Cache Control to "public", see the Force.com Sites documentation for more information on this.

Next we will need to query that contact to get the data record required, we do this with the following code. The code will first query the database, and then it will generate an attachment using the above method. Finally it attaches the new attachment to the contact record and navigates to that record.

        public PageReference XFDFInit() {
            Contact c = [SELECT Id, firstname, lastname, SS_Number__c, birthdate, 
                     phone, Citizenship__c,
                     Country_of_Birth__c, Country_of_Tax_Residence__c, 
                     Government_Identification__c, ID_Number__c,
                     Account.Name, Account.BillingStreet, Account.BillingCity, 
                     Account.BillingState, Account.BillingPostalCode
                     FROM Contact
                     WHERE id = :ApexPages.currentPage().getParameters().get('id')];
	        
	    String xmlContent = getXmlString(c);
	        
	    Attachment attachment = new Attachment();
            attachment.Body = Blob.valueOf(xmlContent);
            attachment.Name = c.lastname + c.firstname + '.XFDF';
            attachment.ParentId = c.Id;
            
            insert attachment;
	                         
	    PageReference contactPage = new PageReference('/' + c.id);
	    contactPage.setRedirect(true);
	    return contactPage;
        }

Notice that we've named the attachment with an XFDF suffix. That will allow users to click on this attachment and launch Adobe Reader properly. Once launched, Reader will automatically merge the document form with the data contained in the XFDF file. If you have a full version of Adobe Acrobat, you will be able to save the merged file.

Finally, we can create a Visualforce page that launches this process, this code is very simple:


<apex:page showHeader="true"
	controller="myXFDFController" 
	action="{!XFDFInit}"
	showHeader="false">
</apex:page>

This page is used under a button to cause the attachment to be created.

Limitations

The current feature set of Adobe Reader will not let users save the PDF document after it is merged, it can only be viewed. Users will require Adobe Acrobat to perform the merge.

Also, there is no way to perform the merge in Apex Code, you must do this in Acrobat Reader or Acrobat if you would like to save the merged document.

This code example is intended to be simple, and not a complete application. Your form may be much more complicated but the overall process should be similar.

Sample Files

You can view a sample PDF/XFDF file pair by downloading this zip file: http://wiki.apexdevnet.com/images/8/8d/Demo_PDF_Form_and_Data.zip

Once downloaded, extract the two files it contains to your desktop. Double-click on the PDF file to view the unpopulated PDF form. Double-click on the XFDF file to view the PDF form populated. Right-click on the XFDF file to see the XFDF data.

Credits

Many thanks to Jesse Lorenz who helped develop this solution on the Force.com platform.

Ron Hess 13:09, 10 December 2008 (PST)