I've always had a bit of a tough time with Java.
From the first time a 'little' java app crippled my production environment at PC World (back in the days of the memory leak prone JVM) to the several minutes weblogic used to take to just start (!!) to some of the amazing class and method spagetti mess I've seen really smart people create . . . well, let's just say I've never been a Java fan.
This is in part why I like XQuery so much -> it's purpose built for content and has just the right tools to get the job done.
But, outside of working with content, Java does do some really neat stuff . . . and does it well.
And, more importantly, it does a lot of stuff XQuery can't.
Let's say you have some XML that has pointers to images and need to create a distribution package with syndication XML *and* resized images.
XQuery has no problem transforming the XML.
And now, using a neat XQuery package called MLJAM developed by MarkLogic's Jason Hunter and Ryan Grimm, XQuery can also resize the images . . . by having Java do it:
import module namespace jam = "http://xqdev.com/jam" at "/mljam/jam.xqy"
import module namespace jamu = "http://xqdev.com/jam-utils" at "/mljam/jam-utils.xqy"jam:start("[java server URL]/mljam/mljam", "", ""),
for $img in //mediaobject/imageobject
let $uri := fn:data($img/imagedata/@fileref)
let $caption := $img/caption
let $image := jamu:image-resize-percent(fn:doc($uri),50, "jpg")
return
<image>
<path>{$uri}</path>
<image-caption>{fn:string($caption)}</image-caption>
<fifty-percent-binary>
{xdmp:base64-encode(xs:string($image))}
</fifty-percent-binary>
</image>
,
jam:end()
In this XQuery, we are taking docbook mediaobject elements, pulling the binary out and, using the MLJAM utilities module to make a new 50% version of the image.
Then we are making a new XML node, including the meta-data, and putting the encoded version of the image right into it.
Neat!
To get this done, the MLJAM utility is, behind the scenes, making a connection to a Java servlet (the jam:start bit) and running some dynamically created java using the BeanShell Llibrary.
For more details (including how to write your own java in addition to the utilities discussed here) see the very good MLAJM tutorial.
Another task content application developers run into all the time is running an XSL:FO engine to make a PDF from XML.
The transformation of XML to XSL:FO is a perfect task for XQuery since we can natively query the XML and dynamically output the new XML.
However, all the best engines to create the actual PDF are Java based applications. So you used to have to create an entire Java japplication just to fetch the newly created XSL:FO from XQuery and send it to the rendering engine.
But not any more.
Using MLJAM, we can made a pdf of the shakespeare plays we loaded in the Tutorial as simply as this:
import module namespace jam = "http://xqdev.com/jam" at "/mljam/jam.xqy"
import module namespace jamu = "http://xqdev.com/jam-utils" at "/mljam/jam-utils.xqy"xdmp:set-response-content-type("application/pdf"),
let $fo :=
for $play in //PLAY
return
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="standard" page-height="11in" page-width="8.5in"
margin-top="1cm" margin-bottom="2cm" margin-left="2.5cm" margin-right="2.5cm">
<fo:region-body margin-top="0.5cm" margin-bottom="0.5cm"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="standard" initial-page-number="1">
<fo:flow font-size="12pt" font-family="Times, New Roman" flow-name="xsl-region-body">
<fo:block font-family="Times, New Roman">
<fo:block text-align="center" font-weight="bold" font-size="26pt"
color="#990033" margin-top="80px">
{fn:string($play/TITLE)}
</fo:block>
<fo:block text-align="center" font-size="12pt" margin-top="400px">
Sample document from XQuery loves Java!
</fo:block>
<fo:block break-before="page"/>
<fo:block font-family="Arial" font-weight="bold" font-size="14pt">
{fn:string($play/TITLE)}
</fo:block>
{for $scene in $play//SCENE
return
<fo:block text-align="left" padding-top="5mm">
<fo:inline font-weight="bold">
{fn:string($scene/parent::ACT/TITLE)}: {fn:string($scene/TITLE)}
</fo:inline>
{for $speech in $scene//SPEECH
return
<fo:block text-align="left" padding-left="5mm" padding-top="5mm">
{fn:string($speech/SPEAKER)}:
{ for $line in $speech/LINE
return
<fo:block text-align="left" padding-top="2mm">
{fn:string($line)}
</fo:block>
}
</fo:block>
}
</fo:block>
}
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
return
jam:start("http://localhost:8080/mljam/mljam", "", ""),
jamu:fop($fo),
jam:end()
The most complex part here is the actual formatting . . . those three little lines at the end are what used to be an *entire* java application!
Just like that, you've got a dynamically generated PDF in your browser and without even a tiny bit of messing with Java.
Putting the power of Java to work within xQuery content applications? Brilliant! (as the guinness guys would say).
Matt
P.S. Thanks to MarkLogic's Frank Rubino for helping me puzzle out how to inline a binary - for more info check out this article.
Comments