Recently my friend Journal VM Template was feeling a little down in the dumps because of his lack of ability when it comes to handling XML content. He was feeling inferior to Journal XSL Template because of this one's superlative ability in dealing with any type of XML content, local and remote.
Not liking to see my friend down in the dumps, because he really has many other likeable features, I decided that it was time for an intervention. I got together with a new friend I'd recently started working with, SAXReaderUtil. SAXReaderUtil is a new and upcomming character around the Liferay codebase, and has tremendous skill when if comes to dealing with XML content.
He can easily get XML from Strings, Files, java.net.URLs, java.io.Readers, InputStreams, and most recently from a plain old String URLs. Not only that, but he can get you Documents with one line, can handle XPATH, do Node sorting, etc.. all in very little code.
Not only that, but all his buddies, Element, Node, and Branch (because he's a relative of dom4j) are all equally great to work with and very skilled.
Well, I'll show some code in a minute, but what I really wanted to tell you was that, I introduced SAXReaderUtil to Journal VM Template and they are getting along very well. So well, in fact, that I'm itching to show you some of the cool stuff these two can do now that they are working together.
Ok, so let's make a new Document from scratch:
#set ($document = $saxReaderUtil.read("<friends/>"))
#set ($root = $document.getRootElement())
#set ($friends = ["Journal VM Template", "SAXReaderUtil", "Document", "Element", "Branch", "Node"])
#foreach ($friend in $friends)
#set ($friendEl = $root.addElement("friend"))
#set ($friendEl = $friendEl.addText($friend))
#end
<pre>$htmlUtil.escape($document.asXML())</pre>
The output should look something like this (but not pretty printed, I did that):
<?xml version="1.0" encoding="UTF-8"?> <friends> <friend>Journal VM Template</friend> <friend>SAXReaderUtil</friend> <friend>Document</friend> <friend>Element</friend> <friend>Branch</friend> <friend>Node</friend> </friends>
Cool eh?
Ok, now suppose we mocked up a whole doc full of content and we want to provide it to some external client, an RSS reader, as a response to an AJAX call, etc.
First off, make sure that the article using the template is on a public page (so it's not gonna give you permission problems to start with). Next, lets add a little bit more code to make this content available as a regular old feed.
#set ($document = $saxReaderUtil.read("<friends/>"))
#set ($root = $document.getRootElement())
#set ($friends = ["Journal VM Template", "SAXReaderUtil", "Document", "Element", "Branch", "Node"])
#foreach ($friend in $friends)
#set ($friendEl = $root.addElement("friend"))
#set ($friendEl = $friendEl.addText($friend))
#end
#if ($request.window-state != "exclusive")
<pre>$htmlUtil.escape($document.asXML())</pre>
<a href="${request.render-url-exclusive}">FEED ME</a>
#else
$document.asXML()
#end
Now, click the "FEED ME" link and see what you get... (view source...)
That's right.. Whoop! Whoop!! Who's your Daddy???
That effectively turns your regular old templates into a relatively simple service end point. Tie that together with the ability to call Liferay's underlying services and you can publish any kind of feed you like... could even provide reports for some remote system which process some of your data blah blah... you get the idea.
But what if you want the template to be a consumer of some data in XML and produce a view of that data. A common scenario is a custom Journal Article list. Let's write some code to do that.
#set ($document = $saxReaderUtil.readURL("http://localhost:8080/lportal/c/journal/get_articles?groupId=14&delta=1"))
<textarea style="height: 800px; width: 500px;">
$document.asXML()
</textarea>
So, I'm making an API call to the backend Journal API to get the most recent article (delta=1) updated in the community with groupId=14. So first off, it's worth noting that it was easy to make the call, we just used the readURL method. Next, we're just dumping the contents into a textarea. This is the first step to see if we have good data to work with. It should look something like this.
Ok, so we were talking about our new friend SAXReaderUtil. It seems he's doing a fine job so far. Let's see what other tricks him and his buddies provide.
Let's get the list of articles using XPATH (of course we have one... but you'd likely have more right?).
#set ($document = $saxReaderUtil.readURL("http://localhost:8080/lportal/c/journal/get_articles?groupId=14&delta=1"))
#set ($root = $document.getRootElement())
#set ($articles = $root.selectNodes("/result-set/result/root"))
<textarea style="height: 800px; width: 500px;">
$articles.get(0).asXML()
</textarea> Now we know our list is right, we can iterate through each article and get some details about each one.
#set ($document = $saxReaderUtil.readURL("http://localhost:8080/lportal/c/journal/get_articles?groupId=14&delta=1"))
#set ($root = $document.getRootElement())
#set ($articles = $root.selectNodes("/result-set/result/root"))
<ul>
#foreach ($article IN $articles)
#set ($articleId = $article.selectSingleNode("dynamic-element[@name='reserved-article-id']/dynamic-content"))
#set ($articleTitle = $article.selectSingleNode("dynamic-element[@name='reserved-article-title']/dynamic-content"))
#set ($articleModifiedDate = $article.selectSingleNode("dynamic-element[@name='reserved-article-modified-date']/dynamic-content"))
#set ($articleAuthorName = $article.selectSingleNode("dynamic-element[@name='reserved-article-author-name']/dynamic-content"))
<li>
<a href="${request.render-url-maximized}${request.portlet-namespace}articleId=${articleId.text}">${articleTitle.text}</a>
<br/>
<span style="font-size: smaller;">${articleAuthorName.text}, ${articleModifiedDate.text}</span>
#end
</ul>
What we get is this:
Ok, we're only showing one... how does it look with more. All we do is modify the API query by setting the delta parameter to something higher. Let's pick 4.
Now notice that the URL's actually work, placing the given article in Maximized mode. You can choose to not go maximized if you like (use ${request.render-url} instead of ${request.render-url-maximized}. And if you use a friendly URL you can target another portlet on the page completely, using the traditional "narrow-side-nav-links vs. wide-side-view-port" model.
Anyway, It's pretty impressive what you can accomplish when friends work together. I'd suggest visiting with Journal VM Template and SAXReaderUtil & Co. as soon as you can take Liferay 5.1.2 for a spin (5.1.x until the official release). All my friends are enjoying their new acquaintances. I hope you enjoy them too.

