This morning I was working on implementing xsl-fo formatting for the xhtml <cite> tag. Typically you want citations to be italicized:
<xsl:template match="cite">
<fo:inline font-style="italic"><xsl:apply-templates/></fo:inline>
</xsl:template>
Of course there is this complication: if the surrounding text is already italicized, then you want the citation font-style to be normal for the purposes of contrast. The first, somewhat naive attempt at addressing this can be found in Doug Tidwell's IBM tutorial (http://www.ibm.com/developerworks/library/x-xslfo2app/#cite):
<xsl:template match="cite">
<xsl:choose>
<xsl:when test="parent::i">
<fo:inline font-style="normal">
<xsl:apply-templates select="*|text()"/>
</fo:inline>
</xsl:when>
<xsl:otherwise>
<fo:inline font-style="italic">
<xsl:apply-templates select="*|text()"/>
</fo:inline>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
This would be OK, except that xsl-fo allows for the font-style attribute in any block or inline tag. So imagine that in a somewhat modified flavor of html, the font-style attribute can appear in any (xhtml strict) block or inline tag which can contain text or children containing text (in addition to appearing in the xsl-fo output). The puzzle I'm trying to solve is how can you then determine whether or not any particular citation should be italicized?
My first stab at solving the problem:
<xsl:template match="cite">
<fo:inline>
<xsl:choose>
<xsl:when test="ancestor::i">
<xsl:variable name="font-style" select="'normal'"/>
</xsl:when>
<xsl:when test="parent::*[@font-style='italic']">
<xsl:variable name="font-style" select="'normal'"/>
</xsl:when>
<xsl:when test="parent::*[@font-style='normal']">
<xsl:variable name="font-style" select="'italic'"/>
</xsl:when>
<xsl:when test="ancestor::*[@font-style='italic']">
<xsl:variable name="font-style" select="'normal'"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="font-style" select="'italic'"/>
</xsl:otherwise>
<xsl:attribute font-style=$font-style/>
<xsl:apply-templates/>
</fo:inline>
</xsl:template>
Of course it's clear that this doesn't work in every case:
<div font-style="italic">
<p font-style="normal">Old, but good science fiction, such as
<b><cite>Stephenson, Neil "Snowcrash"</cite></b>
more text....
</p></div>
The template above would set the font-style of the citation to normal because this condition would be the first one met:
<xsl:when test="ancestor::*[@font-style='italic']">
I've thought about something like
test="count(ancestor::*[@font-style='italic']) - count(ancestor::*[@font-style='normal') mod 2 = 0"
but this doesn't work, either, as the order of tags matters; i.e. it's perfectly legal to do something like this:
<div font-style="italic> ... <p font-style="italic"> ...</p></div>
I know how I would do this with a procedural language: count backwards through the ancestor list incrementing/decrementing an "italic" count variable, but I can't think of any way of doing this in XSL, given that variables are immutable.