Monday, October 20, 2008

Adobe XFDF

Adobe Xml Forms Data Format is an xml format that allows you to fill PDF forms.  I used this in my D&D character generator to allow for easy creation of a printable character sheet in PDF form.

I started with an editable PDF form.  Each field in an editable form has a name of some sort, and if you have access to Adobe LiveCycle Designer, you can view the fields as XML.  All you have to do is open the editable PDF in LiveCycle Designer and click View->XML Source.  This will give you a long XML list detailing all the fields in your form.

UPDATE 2008-11-13: I got an email from someone recently who was creating his editable form using LiveCycle Designer.  It turns out that if you use LiveCycle Designer to build your form, it won't work with XFDF.  If you want to use XFDF, you have to create the form using Acrobat.  LiveCycle Designer forms require that you use XDP (which I have never used).  You can read a bit more about the incompatibilities here.

To specify the values to go into an editable PDF, you create an XFDF file.  The basic format is this:

<?xml version="1.0" encoding="UTF-8"?>
<xfdf xmlns="http://ns.adobe.com/xfdf/" xml:space="preserve">
<f href="http://www.lukerymarz.com/files/CharacterSheet.pdf"/>
<fields>
  <field name="name">
    <value>null</value>
  </field>
  <field name="level">
    <value>1</value>
  </field>
  <field name="class">
    <value>Warlock</value>
  </field>
  <field name="race">
    <value>Tiefling</value>
  </field>
   ...
   ...
   ...
</fields>
</xfdf>

You put this in a text file with an xfdf extension and when you open it, it will reference the pdf in the <f> field and fill in the specified fields.  

So how do you get from the XML LiveCycle Designer gives you to the actual xfdf data.  Well, I didn't want to type a bunch of repetitive lines for each field in the form, so I wrote a little tool to take the LiveCycle xml and spit out ActionScript.  My tool opens the LiveCycle XML, parses each field, and provides a listing with the field type.  It then converts each field to ActionScript code that will append to a string in a my output function.  All I did then was copy the ActionScript code, fill in the specific piece of data for each field (for example, currentCharacter.name for the "name" field), and the output was done.  

There are two caveats I ran into, and the first has to do with spaces.  For each field, the name of that field in the LiveCycle XML has an underscore where a space is.  In the XFDF XML you generate, those underscores need to be replaced with an actual space, otherwise your field won't get filled in.  

The second caveat has to do with arrays.  For example, a part of the ActionScript code my tool generated looks like this:

xfdf += '<field name="class_feature.0"><value>' + Database.Data.currentCharacter. + '</value></field>';
xfdf += '<field name="class_feature.1"><value>' + Database.Data.currentCharacter. + '</value></field>';
xfdf += '<field name="class_feature.2"><value>' + Database.Data.currentCharacter. + '</value></field>';
xfdf += '<field name="class_feature.3"><value>' + Database.Data.currentCharacter. + '</value></field>';
xfdf += '<field name="class_feature.4"><value>' + Database.Data.currentCharacter. + '</value></field>';
xfdf += '<field name="class_feature.5"><value>' + Database.Data.currentCharacter. + '</value></field>';
xfdf += '<field name="class_feature.6"><value>' + Database.Data.currentCharacter. + '</value></field>';


This is an array of class features.  You'd think you could just go through the list, creating:

  <field name="class feature.0">
    <value>sample feature 1</value>
  </field>
  <field name="class feature.1">
    <value>sample feature 2</value>
  </field>

But that is incorrect.  Since this is an array, you have to represent it as one in the xfdf.  The actual output would look like this:

  <field name="class feature">
    <field name="0">
      <value>Eldritch Blast:</value>
    </field>
    <field name="1">
      <value>Edlritch Pact: Choose Fey Pact, Infernal Pact, or Star Pact.</value>
    </field>
    <field name="2">
      <value>Prime Shot: If you are closest to your target, +1 to attack rolls</value>
    </field>
  </field>

And that's it.  If you reference a pdf on a website, you can send only the xfdf to your user, and as long as they have access to your website, when they open the xfdf, Adobe will take care of the rest.  Pretty neat, once you get past the catches.

6 comments:

Sridhar said...

Neat article. Saved tonnes of time for me. Have been searching for ways to show xml data in pdf forms, all online.

Gr8 work.

Unknown said...
This comment has been removed by the author.
Unknown said...

Hey I tried using above technique to my livecycle created forms but it did not work .. it opens with form which is created using acrobat. please reply
-niku

Luke Rymarz said...

Hi Nirav,

I was never able to get LiveCycle edited forms to work with XFDF. I do all my form editing by opening the document in Adobe Acrobat Pro, and the clicking Forms->Add or Edit fields. If you have Acrobat Pro, you may be able to open your LiveCycle generated form in Acrobat Pro and re-save it to get xfdf to work.

There doesn't seem to be much documentation from Adobe on XFDF and troubleshooting when it doesn't work, so you'll have to experiment a bit with it. Let me know if you come up with a LiveCycle-only solution. I'm sure lots of people (including myself) would find it useful.

broodinana said...

I am not able to see the 'f href' node in the XFDF retrieved in Acrobat 9.
Is there any difference in the way we submit XFDF data in Acrobat 7 and 9? (Cuz it works perfectly fine in Acrobat 7).

Unknown said...

Hello,

Very very very nice work!

does anyone knows a method to make an expandable text area into a PDF template instead of a fixed dimension one?

I'll try to explain me better: I'd like to have a text area that expands itself accordling to how much data it have to show (passed trough specific XFDF filed value).

The best way I'd like to see is something like the Microsoft word template, if you insert an external txt file upon it, the txt content writes itself into the designed area and, if data is too much, another document is created from the template with the same structure and the exceeding data filled into

thanks everyone, regards