Newer
Older
XML / latex_calendar.xsl
<?xml version="1.0"?>

<!--
	THE USE OF THIS STYLESHEET IS DEPRECATED AS OF 2012-06-18! It has been replaced by equivalent markup embedded within the overall XML authoring framework. This file will stay here to provide backward compatibility with older markup that uses it.
-->

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

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

	<xsl:strip-space elements="*" />
	
	<xsl:param name="subject-code">INFO</xsl:param>
	<xsl:param name="paper-number" />
	<xsl:param name="paper-year" />
	<xsl:param name="paper-period" />

	<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. -->
						<xsl:text>\multicolumn{</xsl:text>
						<xsl:value-of select="$number-of-columns" />
						<xsl:text>}{c}{\LARGE\textbf{</xsl:text>
						<xsl:apply-templates select="paper" />
						<xsl:text> Paper Calendar, </xsl:text>
						<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>
	
	<xsl:template name="SubjectCode" match="SubjectCode">
		<xsl:value-of select="$subject-code" />
	</xsl:template>

	<xsl:template name="PaperNumber" match="PaperNumber">
		<xsl:value-of select="$paper-number" />
	</xsl:template>

	<xsl:template name="PaperCode" match="PaperCode">
		<xsl:value-of select="$subject-code" />
		<xsl:text> </xsl:text>
		<xsl:value-of select="$paper-number" />
	</xsl:template>

	<xsl:template name="PaperYear" match="PaperYear">
		<!--
			@offset lets us output the year +/- some integer value.
			The input value is truncated and defaults to zero if not
			supplied.
		-->
		<xsl:variable name="add">
			<xsl:value-of select="floor(@offset)" />
			<xsl:if test="not(@offset)">0</xsl:if>
		</xsl:variable>
		<xsl:value-of select="$paper-year + $add" />
	</xsl:template>

	<xsl:template name="PaperPeriod" match="PaperPeriod">
		<xsl:value-of select="$paper-period" />
	</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">
			<xsl:text>\multicolumn{</xsl:text>
			<xsl:value-of select="@columns" />}<xsl:text>{|c|}{</xsl:text>
		</xsl:if>
		<xsl:text>\textbf{</xsl:text>
		<xsl:apply-templates />
		<xsl:text>}</xsl:text>
		<xsl:if test="@columns">
			<xsl:text>}</xsl:text>
		</xsl:if>
		<xsl:if test="position() != last()">
			<xsl:text>	&amp;	</xsl:text>
		</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">
			<xsl:text>\multicolumn{</xsl:text>
			<xsl:value-of select="@columns" />
			<xsl:text>}{|l|}{</xsl:text>
		</xsl:if>
		<xsl:apply-templates />
		<xsl:if test="@columns">
			<xsl:text>}</xsl:text>
		</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>
	
	<!--
		Output an apostrophe.
	-->
	<xsl:template match="apostrophe">
		<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:template match="code">
		<xsl:text>\texttt{</xsl:text>
		<xsl:apply-templates />
		<xsl:text>}</xsl:text>
	</xsl:template>
	
</xsl:stylesheet>