So, you have an RSS feed or Atom XML feed, and you’d like it to look nice when users click on it to view it in a browser.
Historically, the most common way to do this was with XSLT. But you don’t have to use XSLT for this! (You never did, really.)
You can View Source on these examples to see how the magic is done.
Style RSS/Atom feeds in the browser with CSS
Here’s an example Atom feed:
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Example Feed</title>
<link href="http://example.org/"/>
<updated>2003-12-13T18:30:02Z</updated>
<author>
<name>John Doe</name>
</author>
<id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>
<entry>
<title>Atom-Powered Robots Run Amok</title>
<link href="http://example.org/2003/12/13/atom03"/>
<id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
<updated>2003-12-13T18:30:02Z</updated>
<summary>Some text.</summary>
</entry>
</feed>
You can add CSS styles to it by adding a <link> tag with a special xmlns="http://www.w3.org/1999/xhtml" namespace, like this:
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<link rel="stylesheet" href="style.css" xmlns="http://www.w3.org/1999/xhtml" />
<!-- ... the rest of the feed goes here ... -->Or, you can add styles directly in the document with a <style> tag.
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<style xmlns="http://www.w3.org/1999/xhtml"><![CDATA[
* { color: red; }
]]></style>
<!-- ... the rest of the feed goes here ... -->Note: These styles will only display when users navigate directly to your feed URL in their browser. The styles you set here will have no effect on the appearance of your feed in a feed reader.
A Warning About Content-Type
You can only style XML this way when you serve the XML with Content-Type: application/xml or text/xml. If you serve the content with Content-Type: application/rss+xml or Content-Type: application/atom+xml, it won't be processed in Chromium browsers, due to a bug in Blink.
(This restriction also applies to XSLT; you can’t attach an XSLT stylesheet to application/rss+xml or application/atom+xml content.)
Run JavaScript when users browse to your RSS/Atom feeds
To run JavaScript when a browser navigates to your feed, you can add a <script> tag to the <feed> element, as long as you add a special xmlns="http://www.w3.org/1999/xhtml" namespace to it, like this:
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<script src="script.js" xmlns="http://www.w3.org/1999/xhtml" />
<!-- ... the rest of the feed goes here ... -->Or, you can run script inline, like this:
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<script xmlns="http://www.w3.org/1999/xhtml"><![CDATA[
console.log('hello');
]]></script>
<!-- ... the rest of the feed goes here ... -->You can use JavaScript to transform your XML. Here are some ways you might want to transform your XML in JS that would be difficult or even impossible to do in CSS.
- Convert
<content type='html'>into rendered HTML - Add a
<head>element, with a<title>and a<meta name="viewport" content="width=device-width">so your feed looks OK on mobile. - Convert
<title>elements with sibling<link>elements into<a href="${link}">${title}</a>clickable links - Convert
<title>elements into<h1>/<h2>elements (for screen-reader accessibility) - Format date elements (
<published>,<updated>) - Convert person elements (
<author>,<contributor>) into<a href="${link}">${name}</a> - Add some extra header UI. (Perhaps you’d like to include a paragraph explaining what a feed is and how to use it?)
Some of these are possible in pure CSS with clever application of ::before, but, life's too short to mess around with that stuff.
I’ve provided a drop-in example in atom-html-transformer.js and rss-html-transformer.js.
It’s a decent starting point for you to add additional transformations and bring your own CSS.
JavaScript is better than XSL
I’ve written thousands of lines of XSL, and I’m very grateful that I’ll never have to do that again.
XSL is a Turing-complete functional programming language, with <xsl:variable>, <xsl:if>, <xsl:for-each> loops, and <xsl:apply-template> function calls in XML.
It’s a common misconception that XSL is a declarative language, because XSL supports pattern matching. Pattern matching in functional programming can often feel declarative. When XSL is doing trivial, functional transformations, when you keep your hands off of xsl:for-each, XSL feels declarative, and doesn’t feel that bad.
But no clean API is perfectly shaped for UI, so you always wind up having to do arbitrary, non-trivial transformations with tricky imperative uses of for-each to make the output HTML satisfy user requirements.
The problem is: writing imperative code in XSL is awful, especially in a browser, especially compared to writing imperative JavaScript. The in-browser XSL syntax hasn’t evolved in twenty years; JavaScript has had decades of active improvements. No browser includes a built-in debugger for XSL. JavaScript even runs faster than XSL, because it’s had decades of performance enhancements.
JavaScript is also more secure than XSL. (Here’s a video of Ivan Fratric’s presentation on XSLT vulnerabilities.) XPath’s document() function, which downloads a document during processing, is a particularly potent source of vulnerabilities. Major browsers are probably going to remove XSLT in the next year or two, for security reasons. (Apple, Chrome, and Mozilla have all agreed to this.)
The best time to ditch XSL and switch to JavaScript was probably 2005, but the second-best time is now!