Building read/write HTTP resources w/ Exyus, while cool, is sometimes more than you need. In this article, you'll see how you can use the XmlPageResource to create a read-only (GET/HEAD) resource that can act as a 'mashup' of other content from remote sites. This allows you to publish cache-able resources that include content from multiple HTTP end-points, including your own local content.
You can view the online version of the Server-Side Mashup.
Sometimes you want to publish an HTML resource that is a 'mashup' of the contents of several other HTTP resources. A good example is the 'home' page of a web site. It might include the most recent posts to the site's news blog, the list of new members, as well as some home-page static content. Exyus makes creating these mashups easy using the XmlPageResource class. This class is designed to load a single associated XML and XSL document pair. since Exyus supports XInclude and XPointer, the source XML document can contain pointers to other remot resources.
top
The first step in the process is to define the HTTP resource you plan to publish. For this
demo, the URL will be /server-mashup/
serving text/html
. The caching will be set to 60 seconds and
we'll use validation caching to improve performance, too. That's really all we need.
Here's the entire code for the ServerMashUp
class that derives from the base XmlPageResource
base class.
// call up the XML and XSL set to do mashup [UriPattern(@"/server-mashup/\.xcs")] [MediaTypes("text/html")] class ServerMashUp : XmlPageResource { public ServerMashUp() { this.AllowCreateOnPut = false; this.AllowDelete = false; this.AllowPost = false; this.ContentType = "text/html"; this.LocalMaxAge = 60; this.MaxAge = 60; this.TemplateXml = "/server-mashup/index.xml"; this.TemplateXsl = "/server-mashup/index.xsl"; this.UseValidationCaching = true; } }
That's all we need to compile. Next we need to compose the XML and XSL documents that will produce the output we want to show to users.
topThe XML content document is the document that details all the data to display on the page. Since we are showing off the 'mashup' abilities of Exyus, our XML will contain some XInclude statements to pull data from other sources. It will also contain some inline content to show you how to that you don't need XInclude to define content.
For this demo, we'll use two remote resources: USGS Earthquake Center. Both sites offer XML-based feeds that we can use. The USGS site uses Atom and the National Geographic site uses RSS.
Below is the complete XML content document we'll need for the demo:
<?xml version="1.0" encoding="utf-8"?> <root xmlns:x="http://www.w3.org/2003/XInclude"> <local> <root> <h1>Server-Side Mashup w/ XmlPageResource</h1> </root> </local> <nat-geo> <x:include href="http://news.nationalgeographic.com/index.rss" /> </nat-geo> <usgs> <x:include href="http://earthquake.usgs.gov/eqcenter/catalogs/1day-M2.5.xml"/> </usgs> <notes> <x:include href="/xcs/templates/server-mashup/notes.xml" /> </notes> </root>
Note that one of the x:include
elemetns points to a local resource
(notes.xml). This document contains some supporting XHTML content that will appear
within the page. You can also see (in the local
element) some inline
XHTML content. XML content documents can contain direct content that can be rendered
in the transformation. There is no requirement to use x:include
to popupate
your XML content documents.
Now it's time to create an XSL Transformation that will produce XHTML that can be viewed with a common browser.
topIn this step, we'll create an XSL transform document that produces valid XHTML. We'll take it in a couple stages to highlight the process.
The main template rule produces the valid HTML document, head and body along with handling the details of calling other template rules to transform the content from the XML document. Here's how the main template rule looks:
<xsl:template match="/"> <html> <head> <title>Exus Server-Side Mashup</title> <link type="text/css" rel="stylesheet" href="/xcs/files/server-mashup/server-mashup.css"/> </head> <body> <div id="page"> <div id="header"> <xsl:copy-of select="//local/root"/> <address> <strong>Refreshed:</strong> <xsl:value-of select="date:format-date(date:date-time(),'yyyy-MM-dd hh:mm:ss')"/> </address> </div> <div id="news"> <h2> <xsl:value-of select="//nat-geo/rss/channel/title" /> </h2> <dl> <xsl:apply-templates select="//nat-geo/rss/channel/item" /> </dl> </div> <div id="side-bar"> <div id="notes"> <xsl:copy-of select="//notes/root"/> </div> <div id="quakes"> <h2> <xsl:value-of select="//atom:feed/atom:title" /> </h2> <p> <xsl:value-of select="//atom:feed/atom:subtitle"/> </p> <ul> <xsl:apply-templates select="//atom:entry" /> </ul> </div> </div> <hr class="clear"/> </div> </body> </html> </xsl:template>
The content from the National Geographic web site is in RSS format. Here's the rule
to convert RSS item
elements for our page:
<!-- handle national geographic items--> <xsl:template match="nat-geo/rss/channel/item"> <dt> <a href="{link}" title="{pubDate}" target="_blank"> <xsl:value-of select="title"/> </a> </dt> <dd> <xsl:value-of select="description" disable-output-escaping="yes"/> </dd> </xsl:template>
the content from the USGS web site is in Atom format. Here's the rule to handle
Atom entry
elements:
<!-- handle usgs entries --> <xsl:template match="atom:entry"> <li> <a href="{//atom:feed/@xml:base}{atom:link[@rel='alternate']/@href}" title="{atom:updated}" target="_blank"> <xsl:value-of select="atom:title"/> </a> </li> </xsl:template>
That's really all there is. Some additional preamble in the XSL document has been left out here, but you can check out the complete XSL document online.
The only thing left is to spruce up the display using some CSS.
topWe could stop at this point. The demo does what it puports to do - combining multiple HTTP end-points into a single resource. But we must admit, the page looks pretty ugly. Let's add a bit of CSS to give it a better loo-and-feel.
Below is the complete CSS file needed to update the display:
a { color:black; } hr.clear { clear: both; visibility: hidden; } h1, h2, h3, h4, p { margin: 0; padding: 0; } h2, h3, h4 { margin-top: .5em; } dt { font-weight: bold; margin-bottom: .2em; } dd { margin-bottom: .5em; margin-left: .3em; } img { margin-right: .3em; border: 0; } ul { margin: 0; padding: 0; list-style-position: inside; } #header { background-color: silver; border: 1px solid black; padding: .3em; margin: -.3em; } #page { width: 760px; margin: auto; background-color: #e6e6e6; border: 1px solid silver; padding: .3em; } #news { width: 400px; float: left; } #side-bar { width: 300px; float: right; } #notes { background-color:#eee; border: 1px solid silver; padding: 0 .3em; margin-top:.3em; margin-right:-.3em; } #notes h2 { margin-top:.1em; }
And that's the end. Not so bad, eh?
top
In this article, you learned how to use the
XmlPageResource
class to build a 'server-side mashup' that includes content from multiple remote
(and local) HTTP end-points. You learned how to use the x:include
element in the XML Content Document and how to build the XSL Transform Document
to convert the imported content into valid XHTML to display to common browsers.
Finally, you added a bit of CSS to improve the look of the demo page.
Mike Amundsen lives and works as a contract programmer in Kentucky, USA. He currently spends most of his time creating and supporting large-scale web sites running under Windows and ASP.NET. In the past, he spent quite a bit of time as a trainer/speaker and was involved in the writing of several books on programming with Microsoft technologies.
top