Search This Blog

Wednesday 27 August 2014

Calling a RESTful web service from a PDF form.

You can retrieve results of a RESTful web service by sending an HTTP GET request to the URL. Within a PDF form we can use the FormCalc Get function to send an HTTP GET request.  If the service returns XML then we can load the results into a data connection and bind our form elements to it and the results will appear on the PDF form.

In this sample I am using the Google Customs Search service, this allows you to specify a list of URLs and search within that subset.  To be almost useful and related to this blog topic I have included the websites I have found useful when looking for information related to PDF XML forms.

To get an idea what the form is doing paste the following URL (which will perform a search for the word loadXML) into your browser address field, then do a "View Source" on the results to see what this sample form has to deal with.

https://www.googleapis.com/customsearch/v1?key=AIzaSyCESW0ptt79sXXv9Cdz7lLDocNIBTJWH48&cx=015851576802315024878:qkoprvhbpgc&q=image&alt=atom

The important parts of the URL is, q=image, the actual search term and alt=atom, which means the results will be in an atom (XML) feed format (the default is a JSON format).  The other bits are to identify the custom search to use.

The response will be en entry element for each Google search result returned, something like;

 <entry gd:kind="customsearch#result">
  <id>http://adobelivecycledesignercookbookbybr001.blogspot.com/2014/03/using-utilprint-methods.html</id>
  <updated>1970-01-17T07:20:53.790Z</updated>
  <title type="html">Adobe LiveCycle Designer Cookbooks by BR001: Using the &lt;b&gt;util&lt;/b&gt; &lt;b&gt;...&lt;/b&gt;</title>
  <link href="
http://adobelivecycledesignercookbookbybr001.blogspot.com/2014/03/using-utilprint-methods.html" title="adobelivecycledesignercookbookbybr001.blogspot.com"/>
  <summary type="html">Mar 27, 2014 &lt;b&gt;...&lt;/b&gt; var v = util.printx(&amp;quot;9999999999&amp;quot;,&amp;quot;My phone number is (02) 1111 2222&amp;quot;) ... var v = &lt;br&gt;
&lt;b&gt;util&lt;/b&gt;.&lt;b&gt;printf&lt;/b&gt;(&amp;quot;%,105d&amp;quot;, 2)console.println(v), 00002, Prints the&amp;nbsp;...</summary>
  <cse:cacheId>NwQJCo32ZJcJ</cse:cacheId>
  <cse:formattedUrl type="html">adobelivecycledesignercookbookbybr001.blogspot.com/.../using-&lt;b&gt;util&lt;/b&gt;print- methods.html</cse:formattedUrl>
  <cse:PageMap>
   <cse:DataObject type="metatags">
    <cse:Attribute name="viewport" value="width=1100"/>
    <cse:Attribute name="author" value="Bruce"/>
   </cse:DataObject>
   <cse:DataObject type="blogposting">
    <cse:Attribute name="blogid" value="7970679050025899967"/>
    <cse:Attribute name="postid" value="5034164472928527349"/>
    <cse:Attribute name="name" value="Using the util.print methods"/>
    <cse:Attribute name="description" value="Generally we can you display patterns to for formatting but there are times when we have to format values in code, and there are three handy methods in the Adobe Reader API; util.printd()for..."/>
    <cse:Attribute name="articlebody" value="Generally we can you display patterns to for formatting but there are times when we have to format values in code, and there are three handy methods in the Adobe Reader API; util.printd()for..."/>
    <cse:Attribute name="url" value="
http://adobelivecycledesignercookbookbybr001.blogspot.com/2014/03/using-utilprint-methods.html"/>
    <cse:Attribute name="datepublished" value="Thursday, March 27, 2014"/>
   </cse:DataObject>
  </cse:PageMap>
 </entry>


You can play with the search using the public URL, https://www.google.com.au/cse/publicurl?cx=015851576802315024878:qkoprvhbpgc,

NOTE: this is a free service so only 100 searches can be made a day, if you find this useful then you should setup your own custom search and change the key and cx values, in the sample PDF form these values are defined as Form Variables). 

The results of this search will appear in the sample form like;


Security

The user experience will differ depending on the version of Reader (or Acrobat) being used and if you are using Reader standalone or the browser plugin.  With the standalone Reader expect to see a popup message like;


Selecting allow with "Remember this action ..." selected will add the site to "Always Allow" list under Edit ... Preferences ... Trust Manager ... "Internet Access from PDF Files outside the web browser" ... Change Settings.  This dialog has options to always allow or always block, and the option to remove googleapis.com once you have finished playing with this sample.

Retaining state during a xfa.form.remerge(); 

When we click the Search (or More) button the atom feed is loaded into the default data connection and an xfa.form.remerge() is called to bind up the results.  Calling remerge means all properties that are not bound to the data connection revert to their original values. So if a form object starts off being invisible and we make if visible at some point then calling remerge reverts it to invisible.

A way of retaining the form state is to set up a separate dataset and bind to that.  I have done this by typing the definition into the XML Source view.  So this form has the following data structure;

<xfa:datasets xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/">
  <xfa:data xfa:dataNode="dataGroup"/>
  <FormState>
    <SearchTerms/>
    <Feed/>
    <AllinUrl>
      <Value>0</Value>
    </AllinUrl>
    <IncludeDuplicates>
      <Value>0</Value><!-- 0 for not included, otherwise 1 -->
      <Count>0</Count>
      <Presence>hidden</Presence>
    </IncludeDuplicates>
    <Results>
      <Presence>hidden</Presence>
    </Results>
    <DidYouMean>
      <Presence>hidden</Presence>
      <Text/>
      <ToolTip/>
    </DidYouMean>
    <MoreButton>
      <Presence>hidden</Presence>
      <StartIndex>0</StartIndex>
    </MoreButton>
  </FormState>
<dd:dataDescription xmlns:dd="
http://ns.adobe.com/data-description/" dd:name="feed">



Now in the code we can reference these values using an somExpression like;

xfa.datasets.FormState.Feed.value

We can also use the setProperty element to bind directly to the property, so the DidYouMean subform XML Source looks like;


<subform w="199mm" name="DidYouMean">
  <setProperty target="presence" ref="!FormState.DidYouMean.Presence"/>

This means if a spelling correction comes back from the Google search we can set the value in our FormState dataset to visible, call remerge, and the subform will appear.

Default Button

All the other form technologies I have used have allowed you to specify a default action when the enter key is pressed during form filling.  This wouldn’t work for multi-lined text fields and that maybe why a default was not implemented.  But in a simple form like this it can be useful, and is easy to implement now we have event propagation.  Pressing the enter key will cause the exit event to fire, with a commitKey value of 2.  So if we add the following code to the exit event of the Search Term field we can start the search when the enter key is pressed.


if (xfa.event.commitKey === 2) {
    Button.Search.execEvent("click");
}

Binary Result Data

You might want to try and return a binary response, such as the .PNG data of an image, but this does not appear to work.  If you get any response at all it is only the first few characters.

To update pictures in a form you will probably have to base64 encode them on the server first.

Sample

The sample XDP template, fragments, images and schema files can be downloaded in the zip file GoogleSearch.zip.  You don't necessarily need to define a XML Schema, but in this case it helped me understand what the response will look like.

If you just want to play with the sample download GoogleSearch.pdf.






2 comments:

  1. Hey BR001, I am working on a PDF form with LiveCycle to call RESTful web service and having some trouble. Your sample would really help but for some reason either the web link doesn't work or my workplace firewall is blocking it (not sure). Is there any way you can email me the zip? Email is: joeljeezy [at gmail dot com] Thanks. I would really appreciate any help.

    ReplyDelete
  2. You rock. Very good stuff. Thank you for taking the time to put these very valuable resources out there for the rest of us.

    ReplyDelete