Blogger via XSLT

Saturday 15 October 2005

The last few days I've been setting up my wife's brand-new blog. For some reason, I went with Blogger as a technology. Because her site (like this one) is static HTML generated by XSLT on my laptop, I wanted to generate the Blogger template the same way. That way, the template would have the same look and feel as the rest of the site, and when the overall look changes, the template would change too.

Blogger templates are like most other templating systems: they look like HTML files, with strange foreign Blogger-specific tags in them. The problem with generating Blogger templates with XSLT is that the "tags" in the template are not well-formed XML. So I had to resort to some tricks and compromises to make it all work.

The end result works, but is a bit icky in the middle. If you're interested in the details of stuff like this, read on.

Here's a typical piece of a Blogger template:

<Blogger>
   <BlogDateHeader>
      <h3><$BlogDateHeaderDate$></h3>
   </BlogDateHeader>
   <BlogItemTitle>
      <h2>
         <a href="<$BlogItemURL$>"><$BlogItemTitle$></a>
      </h2>
   </BlogItemTitle>

The <Blogger> and <BlogDateHeader> tags are simple enough: they're OK as XML. But the dollar signs in <$BlogDateHeaderDate$> are troublesome, as is the <a> tag at line 7 with the angle brackets in the attribute value.

What I ended up doing was adding these clauses to my stylesheet:

<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0"

    xmlns:b='http://www.stellated.com/blogger'
    xmlns:ba='http://www.stellated.com/bloggerlink'
    xmlns:bd='http://www.stellated.com/bloggerdollar'
    >

<xsl:template match='b:*'>
    <xsl:element name='{local-name()}'>
        <xsl:apply-templates />
    </xsl:element>
</xsl:template>

<xsl:template match='ba:*'>
    <a>
        <xsl:attribute name='href'>
            <xsl:text disable-output-escaping='yes'>&lt;$</xsl:text>
            <xsl:value-of select='local-name()' />
            <xsl:text disable-output-escaping='yes'>$&gt;</xsl:text>
        </xsl:attribute>
        <xsl:copy-of select='@*' />
        <xsl:apply-templates />
    </a>
</xsl:template>

<xsl:template match='bd:*'>
    <xsl:text disable-output-escaping='yes'>&lt;$</xsl:text>
    <xsl:value-of select='local-name()' />
    <xsl:text disable-output-escaping='yes'>$&gt;</xsl:text>
</xsl:template>

The disable-output-escaping attribute is essential here, as we're creating XML-like structures that aren't XML. It lets us output angle brackets as true angle brackets, and put together a "tag" the hard way, flying under the radar of the XML parser that reads the XSLT sheet.

I've created three namespaces: b for ordinary Blogger tags, bd for Blogger tags with dollar signs in them, and ba for a tags that need a blogger tag in the href attribute.

Now I can put this into my page template input file:

<b:Blogger>
   <b:BlogDateHeader>
      <h3><bd:BlogDateHeaderDate/></h3>
   </b:BlogDateHeader>
   <b:BlogItemTitle>
      <h2>
         <ba:BlogItemURL><bd:BlogItemTitle/></ba:BlogItemURL>
      </h2>
   </b:BlogItemTitle>

and the output will be the desired Blogger template tags as shown above. Unfortunately, there's even wierder stuff in typical Blogger templates. They have start tags and end tags individually conditionalized in ways that completely violate XML tag nesting:

<h2>
   <BlogItemURL><a href="<$BlogItemURL$>"></BlogItemURL>
   <$BlogItemTitle$>
   <BlogItemURL></a></BlogItemURL>
</h2>

I didn't even attempt this, since I didn't want the conditionalization anyway. And there are "tags" which expand to attributes for an enclosing tag:

<a href="<$BlogItemCommentCreate$>" <$BlogItemCommentFormOnClick$>>
   <$BlogItemCommentCount$> comments
</a>

That one I completely punted on, resorting to a special-purpose XSLT template for it:

<xsl:template match='bloggercommentlink'>
    <xsl:text disable-output-escaping='yes'>&lt;a href="&lt;$BlogItemCommentCreate$>" &lt;$BlogItemCommentFormOnclick$>></xsl:text>
        <xsl:apply-templates />
    <xsl:text disable-output-escaping='yes'>&lt;/a></xsl:text>
</xsl:template>

Like I said, the end result works. I had to avoid the constructs that were really hairy, but none of them were things I missed.

tagged: » react

Comments

Add a comment:

name
email
Ignore this:
not displayed and no spam.
Leave this empty:
www
not searched.
 
Name and either email or www are required.
Don't put anything here:
Leave this empty:
URLs auto-link and some tags are allowed: <a><b><i><p><br><pre>.