Newer
Older
XML / latex_calendar.xsl
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

	<xsl:output method="text" encoding="ISO-8859-1" media-type="text/plain"/>

	<xsl:strip-space elements="*"/>

	<xsl:variable name="rows-per-week">
		<xsl:value-of select="/calendar/@rows-per-week"/>
		<xsl:if test="not(/calendar/@rows-per-week)">2</xsl:if>
	</xsl:variable>
	
	<xsl:variable name="number-of-weeks">
		<xsl:value-of select="/calendar/@number-of-weeks"/>
		<xsl:if test="not(/calendar/@number-of-weeks)">13</xsl:if>
	</xsl:variable>
	
	<!--
		This is the number of columns in the output table.
	 -->
	<xsl:variable name="number-of-columns">11</xsl:variable>

	<xsl:template match="/">
		\newlength{\numberwidth}
		\settowidth{\numberwidth}{<xsl:number value="$number-of-weeks * 2"/>}
		<xsl:apply-templates/>
	</xsl:template>
	
	<xsl:template match="calendar">
		\begin{center}
			\begin{sideways}
				\resizebox{24cm}{!}{%
					\begin{tabular}{|c|c|c|c|l|c|c|c|c|c|c|}
						<!-- Calendar heading. -->
						\multicolumn{<xsl:value-of select="$number-of-columns"/>}{c}{\LARGE\textbf{<xsl:apply-templates select="paper"/> Paper Schedule, <xsl:apply-templates select="period"/><xsl:text> </xsl:text><xsl:apply-templates select="year"/>}}	\\
						\multicolumn{<xsl:value-of select="$number-of-columns"/>}{c}{}	\\
						\hline
		
						<!-- The calendar itself. -->
						<xsl:apply-templates select="header"/>
						\hline\hline
						<xsl:apply-templates select="body"/>
						\hline\hline
						<xsl:apply-templates select="footer"/>
					\end{tabular}%
				}
			\end{sideways}
		\end{center}
	</xsl:template>
	
	<!--
		Header/footer rows for the calendar table. To get proper table
		headings/footings, use HEADING/FOOTING. For other text, use NOTE.
	-->
	<xsl:template match="header|footer">
		<xsl:apply-templates/>	\\ \hline
	</xsl:template>
	
	<!--
		A table heading or footing, bolded, centered, etc.
	-->
	<xsl:template match="heading|footing">
		<xsl:if test="@columns">
			\multicolumn{<xsl:value-of select="@columns"/>}{|c|}{%
		</xsl:if>
		\textbf{<xsl:apply-templates/>}%
		<xsl:if test="@columns">
			}
		</xsl:if>
		<xsl:if test="position() != last()">
			&amp;
		</xsl:if>
	</xsl:template>
	
	<!--
		A miscellaneous piece of text to be inserted somewhere in the
		calendar table.
	-->
	<xsl:template match="note">
		<xsl:if test="@columns">
			\multicolumn{<xsl:value-of select="@columns"/>}{|l|}{%
		</xsl:if>
		<xsl:apply-templates/>%
		<xsl:if test="@columns">
			}
		</xsl:if>
	</xsl:template>
	
	<!--
		A week in the calendar. Each week has an associated number
		(automatically generated) and a date range, and spans some
		defined number of rows (default 2). The week number and
		date range are only generated for the first of these rows.
	-->
	<xsl:template match="week">
		<xsl:for-each select="row">
			
			<!--
				If we're going to start a new section, draw a rule under
				the previous section to separate them.
			-->
			<xsl:if test="count(section) != 0">
				\cline{3-3}
			</xsl:if>

			<!-- Output the week number and dates columns. -->
			<xsl:choose>
				<xsl:when test="position() = 1">
					<!-- Week number, first row only. -->
					\multirow{<xsl:value-of select="$rows-per-week"/>}{*}{%
						\makebox[\numberwidth][c]{%
							<xsl:number value="1 + count(preceding::week[not(@holiday)])"/>%
						}%
					}&amp;
	
					<!-- Date range, first row only. -->
					\multirow{<xsl:value-of select="$rows-per-week"/>}{*}{%
						\begin{tabular}{c}%
							<xsl:apply-templates select="../dates"/>%
						\end{tabular}%
					}&amp;
				</xsl:when>
				<xsl:otherwise>
					&amp;&amp;
				</xsl:otherwise>
			</xsl:choose>
			
			<!--
				We have to apply each of the sub-templates manually, not
				so much to ensure the correct ordering, but so that we
				can output empty cells when an element is missing.
			-->
			<xsl:apply-templates select="section"/>
			&amp;

			<xsl:apply-templates select="lecture"/>
			<xsl:if test="count(lecture) = 0">
				\multicolumn{2}{|c|}{}
			</xsl:if>
			&amp;

			<xsl:apply-templates select="reading"/>
			&amp;

			<!--
				Labs and tutorials are tricky because we can't just output
				two empty cells and continue. If the previous LABORATORY or
				TUTORIAL entry is empty, then outputting two empty cells
				would look wrong (because these usually span at least two
				rows). The converse is also true.
			-->
			<xsl:apply-templates select="laboratory"/>
			<xsl:if test="count(laboratory) = 0">
				<xsl:choose>
					<xsl:when test="not(preceding::row[1]/laboratory/node())">
						\multicolumn{2}{|c|}{}
					</xsl:when>
					<xsl:otherwise>
						&amp;
					</xsl:otherwise>
				</xsl:choose>
			</xsl:if>
			&amp;

			<xsl:apply-templates select="tutorial"/>
			<xsl:if test="count(tutorial) = 0">
				<xsl:choose>
					<xsl:when test="not(preceding::row[1]/tutorial/node())">
						\multicolumn{2}{|c|}{}
					</xsl:when>
					<xsl:otherwise>
						&amp;
					</xsl:otherwise>
				</xsl:choose>
			</xsl:if>
			&amp;
			
			<xsl:apply-templates select="assessment"/>

			<!-- Note assumption that a lecture is always a single row. -->
			\\ \cline{4-5}
			
			<xsl:if test="position() = $rows-per-week">
				\cline{1-2}\cline{6-6}\cline{11-11}
				<xsl:if test="not(preceding::row[1]/laboratory/@rows)">
					\cline{7-8}
				</xsl:if>
				<xsl:if test="not(preceding::row[1]/tutorial/@rows)">
					\cline{9-10}
				</xsl:if>
			</xsl:if>
			
		</xsl:for-each>
	</xsl:template>
	
	<!--
		Weeks that are holidays have no week number or date range, just
		a text description.
	-->
	<xsl:template match="week[@holiday]">
		\hline\hline
		\multicolumn{<xsl:value-of select="$number-of-columns"/>}{|c|}{%
			\multirow{2}{*}{\LARGE\textsf{\textbf{<xsl:apply-templates/>}}}%
		}	\\
		\multicolumn{11}{|c|}{}	\\
		\hline\hline
	</xsl:template>
	
	<!--
		Output a calendar entry for a lecture. Note that lectures are
		always assumed to span a single row. Lectures are automatically
		numbered.
	-->
	<xsl:template match="lecture[node() and not(@holiday)]">
		<xsl:number value="1 + count(preceding::lecture[node() and not(@holiday)])"/>
		&amp;
		<xsl:apply-templates/>
	</xsl:template>
	
	<!--
		Output a calendar entry for a lecture that occurs on a holiday.
		These aren't numbered.
	-->
	<xsl:template match="lecture[@holiday]">
		\multicolumn{2}{|c|}{\textsf{\textbf{<xsl:apply-templates/>}}}
	</xsl:template>
	
	<!--
		Output an empty lecture cell.
	-->
	<xsl:template match="lecture[not(node())]">
		\multicolumn{2}{|c|}{}}
	</xsl:template>
	
	<!--
		Output a calendar entry for a laboratory. Laboratories are
		automatically numbered.
	-->
	<xsl:template match="laboratory[node()]">
		<xsl:variable name="num-rows">
			<xsl:value-of select="@rows"/>
			<xsl:if test="not(@rows)">
				<xsl:value-of select="$rows-per-week"/>
			</xsl:if>
		</xsl:variable>

		\multirow{<xsl:value-of select="$num-rows"/>}{*}{%
			\makebox[\numberwidth][c]{%
				<xsl:number value="1 + count(preceding::laboratory[node()])"/>%
			}%
		}&amp;

		\multirow{<xsl:value-of select="$num-rows"/>}{*}{%
			\begin{tabular}{c}%
				<xsl:apply-templates/>%
			\end{tabular}%
		}
	</xsl:template>
	
	<!--
		Output a calendar entry for a tutorial. Tutorials are
		automatically numbered.
	-->
	<xsl:template match="tutorial[node()]">
		<xsl:variable name="num-rows">
			<xsl:value-of select="@rows"/>
			<xsl:if test="not(@rows)">
				<xsl:value-of select="$rows-per-week"/>
			</xsl:if>
		</xsl:variable>

		\multirow{<xsl:value-of select="$num-rows"/>}{*}{%
			\makebox[\numberwidth][c]{%
				<xsl:number value="1 + count(preceding::tutorial[node()])"/>%
			}%
		}&amp;

		\multirow{<xsl:value-of select="$num-rows"/>}{*}{%
			\begin{tabular}{c}%
				<xsl:apply-templates/>%
			\end{tabular}%
		}
	</xsl:template>
	
	<!--
		Output an empty laboratory/tutorial cell.
	-->
	<xsl:template match="laboratory[not(node())]|tutorial[not(node())]">
		<xsl:variable name="num-rows">
			<xsl:value-of select="@rows"/>
			<xsl:if test="not(@rows)">
				<xsl:value-of select="$rows-per-week"/>
			</xsl:if>
		</xsl:variable>

		\multicolumn{2}{|c|}{\multirow{<xsl:value-of select="$num-rows"/>}{*}{}}
	</xsl:template>
	
	<!--
		Output a calendar entry for a section, reading or asssement (all
		use the same formatting).
	-->
	<xsl:template match="section[node()]|reading[node()]|assessment[node()]">
		<xsl:variable name="num-rows">
			<xsl:value-of select="@rows"/>
			<xsl:if test="not(@rows)">
				<xsl:value-of select="$rows-per-week"/>
			</xsl:if>
		</xsl:variable>

		\multirow{<xsl:value-of select="$num-rows"/>}{*}{%
			\begin{tabular}{c}%
				<xsl:apply-templates/>%
			\end{tabular}%
		}
	</xsl:template>
	
	<!--
		Output an empty section, reading or assessment cell.
	-->
	<xsl:template match="section[not(node())]|reading[not(node())]|assessment[not(node())]">
		<xsl:variable name="num-rows">
			<xsl:value-of select="@rows"/>
			<xsl:if test="not(@rows)">
				<xsl:value-of select="$rows-per-week"/>
			</xsl:if>
		</xsl:variable>

		\multirow{<xsl:value-of select="$num-rows"/>}{*}{}
	</xsl:template>
	
	<!--
		Generate a link.
	-->
<!-- 	<xsl:template match="link"> -->
<!-- 		<a> -->
<!-- 			<xsl:attribute name="href"> -->
<!-- 				<xsl:value-of select="@href"/> -->
<!-- 			</xsl:attribute> -->
<!-- 			<xsl:apply-templates/> -->
<!-- 		</a> -->
<!-- 	</xsl:template> -->
	
	
	<!--
		Wrap quotes around a string. If the attribute SINGLE is set to
		"yes", use single quotes instead of double.
	-->
	<xsl:template match="quote">
		<xsl:choose>
			<xsl:when test="@single = 'yes'">
				<xsl:text>`</xsl:text>
			</xsl:when>
			<xsl:otherwise>
				<xsl:text>``</xsl:text>
			</xsl:otherwise>
		</xsl:choose>
		<xsl:apply-templates/>
		<xsl:choose>
			<xsl:when test="@single = 'yes'">
				<xsl:text>'</xsl:text>
			</xsl:when>
			<xsl:otherwise>
				<xsl:text>''</xsl:text>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>
	
	<!--
		Output an ampersand character.
	-->
	<xsl:template match="ampersand">
		<xsl:text>\&amp;</xsl:text>
	</xsl:template>
	
	<!--
		Output an en-dash entity character.
	-->
	<xsl:template match="endash">
		<xsl:text>--</xsl:text>
	</xsl:template>
	
	<!--
		Output a section symbol character.
	-->
	<xsl:template match="sect">
		<xsl:text>\S{}</xsl:text>
	</xsl:template>
	
	<!--
		Output a hash character.
	-->
	<xsl:template match="hash">
		<xsl:text>\#</xsl:text>
	</xsl:template>
	
	<!--
		Miscellaneous elements to be mapped straight through.
	-->
	<xsl:template match="strong|b">
		<xsl:text>\textbf{</xsl:text>
		<xsl:apply-templates/>
		<xsl:text>}</xsl:text>
	</xsl:template>
	
	<xsl:template match="em|i">
		<xsl:text>\emph{</xsl:text>
		<xsl:apply-templates/>
		<xsl:text>}</xsl:text>
	</xsl:template>
	
	<xsl:template match="u">
		<xsl:text>\underline{</xsl:text>
		<xsl:apply-templates/>
		<xsl:text>}</xsl:text>
	</xsl:template>
	
	<xsl:template match="br">
		<xsl:text>\\</xsl:text>
	</xsl:template>
	
</xsl:stylesheet>