The AGORA project (this one, not to be confused with this other one nor even this other one again) has defined a very simple TEI XML schema for scholarly publishing. In this series of blog entries, I report my attempts to process a set of documents which conform to that schema into PDF and other formats, using the TEI stylesheet library. My environment is a laptop running Ubuntu 10.04, on which I have installed the 5.1.4 release of the tei-xsl package and most of the texlive Ubuntu packages (versions dating from July 2009 according to dpkg).
On the train to London this morning, I wrote a Makefile which validates each file and, if valid, then processes it using the teitolatex and xelatex commands. This produced something not entirely discouraging, with the following obvious things to fix:
- some of my files had numbered headings and others didn’t. By default the stylesheets added numbers willy nilly. I need to switch this behaviour off.
- some of my files used <byline> in the header to indicate the affiliation for an author, like this:
<byline><docAuthor>Fred Flintstone </docAuthor> Euphoria State University, Kansas</byline>.
By default, the stylesheets clearly have no idea what to do with the text fragment following the <docAuthor>, and therefore spit it out on a page of its own.
I learned at the excellent MUTEC workshop last week that the recommended way of modifying these stylesheets is to set up a new “profile”, so I duly visited the directory /usr/share/xml/tei/stylesheet/profiles and created a new folder there called /usr/share/xml/tei/stylesheet/profiles/agora (somewhat to my surprise this did not require root access). I then copied the existing default specifications for each of the target transformations I thought I might use in my Agora work into this folder. Like this:
$cd /usr/share/xml/tei/stylesheet/profiles $mkdir agora $cp -r default/latex agora $cp -r default/docx agora $cp -r default/oo agora
The directory names (latex, docx, etc.) are not particularly well publicized: I worked out by inspection that “oo” must be the one invoked by the command “teitoodt”… presumably at some point it will be renamed Liboff vel sim.
Anyway, this setup should mean that if I now do e.g.
$teitolatex --profile=agora foo.xml
I should get the same result as I would if I left out the –profile … and so indeed I do. Good. Time to start messing about.
I take a peek into the contents of my agora/latex folder. It contains just one file, called to.xsl — which presumably controls the conversion from tei to latex. One day maybe some clever person will add a file called from.xsl which does the opposite. Or not.
The file is rather dull: all it does is remind me that the file is copyright TEI Consortium 2008, and that the library it invokes is “distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY”. Fair enough. It also loads the stylesheet at
../../../latex2/tei.xsl but all it does to modify that is set some mysterious parameter called reencode to false. So clearly I am at liberty to add further modifications in this file… or will be once I have changed permissions on the file.
../../../latex2 (i.e. /usr/share/xml/tei/stylesheet/latex2, sibling of the profiles directory) is the directory with the real biz. It contains files named for most TEI modules, as well as promising looking files like tei-param.xsl. A little sniffing around, and I have discovered the XSL template for procesing the TEI <head> element inside the file core.xsl, which contains the following magic:
<xsl:choose> <xsl:when test="ancestor::tei:floatingText">Star</xsl:when> <xsl:when test="parent::tei:div/@rend='nonumber'">Star</xsl:when> <xsl:when test="ancestor::tei:back and $numberBackHeadings='false'">Star</xsl:when> <xsl:when test="$numberHeadings='false' and ancestor::tei:body">Star</xsl:when> <xsl:when test="ancestor::tei:front and $numberFrontHeadings='false'">Star</xsl:when> </xsl:choose>
That looks to me suspiciously like there should be a parameter called numberHeadings which I should set to false in order to suppress those pesky generated section numbers. (Of course, I’d have found that out immediately if I’d bothered to read the documentation, but …)
Back in my file profiles/agora/latex/to.xsl, I add the following line
<xsl:param name="numberHeadings">false</xsl:param>
and then regenerate the PDF, using the tweaked stylesheet in my agora profile:
teitolatex --profile=agora aaberge_2007.xml xelatex aaberge_2007.tex
Bingo! no numbering. This could maybe be easier than it looks…
My second problem is trickier. The challenge and the delight of the TEI is precisely its open-endedness, and so it often happens that something which looks plausible in TEI has no obvious translation in some other markup system, such as LaTeX. In my case, how *should* the <byline> element be processed? A grep through the LaTeX directory shows me that at present there is no template at all for it, so my hands are comparatively untied. My first thought is just to add a template like the following to my file:
<xsl:template match="tei:byline/text()"> \author{<xsl:value-of select="."/>} </xsl:template>
on the assumption that the bit of text inside the byLine elements might as well be treated in the same way as an author as anything else. But LaTeX is not so liberal: when it finds that I have generated
\title{The Semantic Web in a philosophical perspective}\author{Terje Aaberge} \author{, Sogndal, Norway}
it simply ignores the first \author. This suggests that I cannot solve this without learning more about LaTeX than I really want to.
Maybe I can modify the existing template for <docAuthor> to deal with this special case. In the file header.xsl there is a template like this
<xsl:template match="tei:docAuthor"> <xsl:if test="not(preceding-sibling::tei:docAuthor)"> <xsl:text>\author{</xsl:text> </xsl:if> <xsl:apply-templates/> <xsl:choose> <xsl:when test="count(following-sibling::tei:docAuthor)=1"> and </xsl:when> <xsl:when test="following-sibling::tei:docAuthor">, </xsl:when> </xsl:choose> <xsl:if test="not(following-sibling::tei:docAuthor)"> <xsl:text>}</xsl:text> </xsl:if> </xsl:template>
It’s a horrible kludge, but if I insert the following before the final <xsl:if> element, it should make sure I output any following sibling text fragment before outputting the }
<xsl:if test="parent::tei:byline and (following-sibling::text())"> <xsl:value-of select="following-sibling::text()"/> </xsl:if>
I therefore copy the whole of the <xsl:template> for docAuthor into my to.xsl file, add the above clause, and blow me down it (nearly) works. I had, of course, forgotten to suppress a second appearance of those pesky text fragments caused by the default processing for <byline>. One more template:
<xsl:template match="tei:byline/text()"/>
fixes that.
Of course, the more I look at this, the less I like it. A much better solution would be to tag the affiliation data as such in the XML source, using an element such as <affiliation> perhaps, and then process it correctly into whatever LaTeX provides for the treatment of such things. But that would, as aforesaid, require some research into what LaTeX can do, as well as changing the Agora schema.
Not a bad way to pass the train journey to Paris, especially when surrounded by kids returning home after the half term hols.