X

Technical info and insight on using Oracle Documaker for customer communication and document automation

Embedding Dynamic Maps in Documaker

Andy Little
Technical Director

Recently a colleague asked if we could embed maps into Documaker output. Being a tech person, I naturally replied, "Of course!" and then I thought about that for a moment and followed that up with, "Wait, what do you mean 'maps'?" What followed was a mini-requirements definition discussion in which we determined that the what we want is:

  • a dynamically generated map from a third party service
  • using data provided in the extract (e.g. an address)
  • rendered into the output (e.g. a PDF)
  • using Documaker Standard Edition

We also discuss some additional use cases that I won’t cover in this post, but will in the future:

  • Documaker Mobile (responsive HTML) output
  • Documaker Enterprise Edition workflow

After understanding my particular requirements, the first thing I needed to do was determine which third party service I would use, which prompted another delve into requirements. Such a service would need to:

  • Be callable via HTTP
  • Support non-geocoded addresses - my data might not be 100% correct and I need the service correct the address for me. In a real-world scenario this is probably not the case as you would not want to risk putting the wrong map in your output, so you'll be sure your extract data already contains a corrected address.
  • Return an image suitable for embedding (if a non-web ready image is returned, we could amend this in our data enrichment flow, but having a web-ready image simplifies things)
  • Be cheap and easy to implement. Ideally I mean < 20 lines of code. I want this to be simple to illustrate. We can get deep into implementation code later, but to stand this up and illustrate things it should be as simple as possible (ASAP) but no simpler.

I settled on a popular mapping API provided by Google. It’s feature-rich, and easy to implement. All you need is a Google API key which is tied to your Google account… and that’s where this experiment goes a little wonky. Why? Well, because my Google account is my personal account and I don’t have a corporate Google account. If you keep your API usage below a certain threshold, your queries will remain free, so this is good for extremely limited development testing. If you decide to go this route, you’ll definitely want to have a corporate Google account for using this feature. I’ve learned that Oracle has a similar maps API that uses a wholly different licensing model, so I’ll explore that in a future post.

To use the Google Maps API:

Next, you’ll create a data enrichment program. For my “less than 20 lines of code” requirement, I chose to implement this in PowerShell (yes, PowerShell!) I created this script:

Add-Type -AssemblyName System.Web

[xml]$ef = Get-Content $args[0] 
$addr = "$($ef.DocumentRequest.Addressees.Addressee.AddrLine1) $($ef.DocumentRequest.Addressees.Addressee.AddrLine2), $($ef.DocumentRequest.Addressees.Addressee.City), ($ef.DocumentRequest.Addressees.Addressee.State) $($ef.DocumentRequest.Addressees.Addressee.PostalCode) $($ef.DocumentRequest.Addressees.Addressee.Country)"

$addr = [System.Web.HttpUtility]::UrlEncode($addr)
$key = $args[1]
$out = $args[2]

$url = "https://maps.googleapis.com/maps/api/staticmap?center=$addr&zoom=13&size=300x300&maptype=roadmap&format=jpg&key=$key"

$wc = New-Object System.Net.WebClient
$wc.DownloadFile($url, $out)

That’s 10 lines of code, not including whitespace. Two things are important to note here: the call to this program expects three arguments:

  1. The path and filename of the extract data file
  2. The Google API key
  3. The location of the output file that should be written.

In my code above, you can see where I have concatenated the address lines in the extract data into a non-geocoded address variable $addr, which I use later when I call the Google API. This call is on the line in bold, where I have specified a size for my map as 300x300, and a format of jpg. I have also included the API key as a variable, which should be passed as the second argument. Finally, the response to this web call is downloaded into the file specified in the third argument. I ran a quick test and can see my image is being downloaded as a JPG:

Screen capture of Windows Explorer showing the downloaded map JPG

Now, depending on what your map service provides, you may need to convert the image from one format to another. ImageMagick is a multi-platform, open source image processing application that we can download and install, and will give us a simple command we can call to perform the necessary conversion based on the file extension (e.g. input.jpg output.tif). However, since the Google API returns a JPG, and we can import that directly, we don’t need to do this — I’m just leaving this info here in case it’s needed:

convert <input file> <output file>

What remains at this point is to get the map image into Documaker’s output. There are a number of ways to do this, but the way I’ve done it in my example is a simple process.

  • Add a placeholder image onto a section. I call the image “PLACEHOLDER”.

Form and Section in Documaker Studio, showing Logo placeholder.

  • Add a PostTransDAL call in my JDT to invoke a DAL script. I’m going to say that’s a total of 11 lines of code (even thought strictly speaking this isn’t code).
;PostTransDAL;2;call("AddMapToLogo");;
  • The DAL script will swap out the existing logo identified by the name PLACEHOLDER on a section called MAP for a file on disk that exists in the FORMS subdirectory of the MRL. Now we’re up to 12 lines of code. Side note: if you need it, the DAL reference guide is available here.
ChangeLogo("embedmap.jpg","PLACEHOLDER","MAP")

Finally, we need to string together the workflow, which for Standard Edition is normally done in a shell script (e.g. a BAT or CMD file): 

    @echo off
    setlocal
    
    @rem Please set your Google Maps API key 
    set KEY="" 
    set MRLDIR="c:\fap\mstrres\dmres"
    set EXTRFILE=%MRLDIR%\INPUT\map.xml
    set OUT=%MRLDIR%\forms\embedmap.jpg"
    
    cd %MRLDIR%
    del data\*.* /q

    powershell.exe -file ".\GetMap.ps1" %EXTRFILE% %KEY% %OUT%
    @REM convert %OUT% %MRLDIR%\forms\embedmap.jpg

    @REM assumes FSIUSER.INI is used, and JDT is configured for single-step to run
    @REM GENTRAN, GENDATA, and GENPRINT.
    gendaw32 

In the lines above, I call the PowerShell script, and pass three arguments to obtain the JPG of the map (remember to add your API key). I have commented out the call to convert since we don’t need. I’m going to say that the above does not constitute lines of code, since we’re just calling a program, but let’s say we have one additional line of code since we are having to call PowerShell. At the end of the shell script Documaker executes in single-step mode (which combines GENTRAN, GENDATA and one or more subsequent Documaker components such as GENPRINT). The PostTransDAL script is called by the JDT command, which swaps the map. In the output PDF we can see the results, all in 13 lines of code:

PDF of Documaker output showing embedding map image.

Now, it should be noted that what I have demonstrated above relies on statically-named intermediary files. If you were operating strictly in a single batch process environment, it would be fine as-is. But if you are running multiple Gendata processes, or using IDS to front any processes, you would need to have dynamically-named intermediary files that ideally use information from the extract data to uniquely name the map JPG file. I hope you’ve found this informative and useful, as it shows how you can take an older system and add new functionality to it to support your business requirements.

Stay tuned for a post where I get into Oracle’s Map API!

Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.