The following XSLT transformation converts an HTML file to XSL Formatting Objects, which can later be transformed to a PDF file.
This particular transformation is customized to work with the
“green sheet” for this course. The green sheet
uses Cascading Style Sheets. For example, because my
stylesheet specifies
.center {text-align: center;},
I can center a paragraph by
saying any of:
<p align="center"> <p style="text-align: center;"> <p class="center">
You will see evidence of this in the set-alignment
and set-pagebreak templates.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:variable name="pagewidth" select="21.5"/>
<xsl:variable name="bodywidth" select="19"/>
<xsl:template match="html">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="mainPage"
page-height="27.9cm"
page-width="{$pagewidth}cm"
margin-left="1cm"
margin-right="1cm"
margin-top="1cm"
margin-bottom="1cm">
<fo:region-before extent="1cm"/>
<fo:region-after extent="1cm"/>
<fo:region-body
margin-top="1cm"
margin-bottom="1cm" />
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="mainPage" initial-page-number="1">
<xsl:apply-templates />
</fo:page-sequence>
</fo:root>
</xsl:template>
<xsl:template match="head/title">
<fo:static-content flow-name="xsl-region-before">
<fo:block font-family="serif" font-size="10pt"
text-align="center">
<xsl:value-of select="."/>
</fo:block>
</fo:static-content>
<fo:static-content flow-name="xsl-region-after">
<fo:block font-family="serif" font-size="10pt"
text-align="center">
Page <fo:page-number />
</fo:block>
</fo:static-content>
</xsl:template>
<xsl:template match="body">
<fo:flow flow-name="xsl-region-body" font-family="serif"
font-size="10pt">
<xsl:apply-templates/>
</fo:flow>
</xsl:template>
<xsl:template match="blockquote">
<fo:block
space-before="6pt" space-after="6pt"
margin-left="2em" margin-right="2em">
<xsl:call-template name="set-pagebreak"/>
<xsl:apply-templates/>
</fo:block>
</xsl:template>
<xsl:template match="h1">
<fo:block font-size="18pt">
<xsl:call-template name="set-alignment"/>
<xsl:call-template name="set-pagebreak"/>
<xsl:apply-templates/>
</fo:block>
</xsl:template>
<xsl:template match="h2">
<fo:block font-size="14pt">
<xsl:call-template name="set-alignment"/>
<xsl:call-template name="set-pagebreak"/>
<xsl:apply-templates/>
</fo:block>
</xsl:template>
<xsl:template match="h3">
<fo:block font-size="12pt" font-weight="bold"
space-before="6pt">
<xsl:call-template name="set-alignment"/>
<xsl:call-template name="set-pagebreak"/>
<xsl:apply-templates/>
</fo:block>
</xsl:template>
<xsl:template match="h4">
<fo:block font-weight="bold" space-before="1mm">
<xsl:call-template name="set-alignment"/>
<xsl:call-template name="set-pagebreak"/>
<xsl:apply-templates/>
</fo:block>
</xsl:template>
<xsl:template name="set-alignment">
<xsl:choose>
<xsl:when test="@align='left' or contains(@class,'left')">
<xsl:attribute name="text-align">start</xsl:attribute>
</xsl:when>
<xsl:when test="@align='center' or contains(@class,'center')">
<xsl:attribute name="text-align">center</xsl:attribute>
</xsl:when>
<xsl:when test="@align='right' or contains(@class,'right')">
<xsl:attribute name="text-align">end</xsl:attribute>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template name="set-pagebreak">
<xsl:if test="contains(@style, 'page-break-before')">
<xsl:attribute name="break-before">page</xsl:attribute>
</xsl:if>
<xsl:if test="contains(@style, 'page-break-after')">
<xsl:attribute name="break-after">page</xsl:attribute>
<xsl:message><xsl:value-of select="@style"/></xsl:message>
</xsl:if>
</xsl:template>
<xsl:template match="div">
<fo:block>
<xsl:if test="@class='bordered'">
<xsl:attribute name="border-width">1pt</xsl:attribute>
<xsl:attribute name="border-style">solid</xsl:attribute>
</xsl:if>
<xsl:call-template name="set-alignment"/>
<xsl:call-template name="set-pagebreak"/>
<xsl:apply-templates/>
</fo:block>
</xsl:template>
<xsl:template match="p">
<fo:block space-before="4pt" space-after="4pt">
<xsl:call-template name="set-alignment"/>
<xsl:call-template name="set-pagebreak"/>
<xsl:apply-templates/>
</fo:block>
</xsl:template>
<xsl:template match="ol">
<fo:list-block provisional-distance-between-starts="10mm"
provisional-label-separation="5mm"
space-before="6pt" space-after="6pt">
<xsl:call-template name="set-pagebreak"/>
<xsl:apply-templates/>
</fo:list-block>
</xsl:template>
<xsl:template match="ol/li">
<xsl:variable name="indention"
select="5*count(ancestor::ol)"/>
<fo:list-item space-after="1mm">
<fo:list-item-label start-indent="{$indention}mm" end-indent="label-end()">
<fo:block>
<xsl:choose>
<xsl:when test="../@type != ''">
<xsl:number format="{../@type}"/>.
</xsl:when>
<xsl:otherwise>
<xsl:number format="1"/>.
</xsl:otherwise>
</xsl:choose>
</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="body-start()">
<fo:block>
<xsl:apply-templates/>
</fo:block>
</fo:list-item-body>
</fo:list-item>
</xsl:template>
<xsl:template match="ul">
<fo:list-block provisional-distance-between-starts="3mm"
provisional-label-separation="1mm"
space-before="6pt" space-after="6pt">
<xsl:call-template name="set-pagebreak"/>
<xsl:apply-templates/>
</fo:list-block>
</xsl:template>
<xsl:template match="ul/li">
<fo:list-item space-after="1mm">
<fo:list-item-label start-indent="5mm">
<xsl:choose>
<xsl:when test="../@type ='disc'">
<fo:block>•</fo:block>
</xsl:when>
<xsl:when test="../@type='square'">
<fo:block font-family="ZapfDingbats">n</fo:block>
</xsl:when>
<xsl:when test="../@type='circle'">
<fo:block font-family="ZapfDingbats">m</fo:block>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="count(ancestor::ul) = 1">
<fo:block>•</fo:block>
</xsl:when>
<xsl:when test="count(ancestor::ul) = 2">
<fo:block font-family="ZapfDingbats">m</fo:block>
</xsl:when>
<xsl:otherwise>
<fo:block font-family="ZapfDingbats">n</fo:block>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</fo:list-item-label>
<fo:list-item-body start-indent="body-start()">
<fo:block>
<xsl:apply-templates/>
</fo:block>
</fo:list-item-body>
</fo:list-item>
</xsl:template>
<xsl:template match="dl">
<fo:block>
<xsl:call-template name="set-pagebreak"/>
<xsl:apply-templates/>
</fo:block>
</xsl:template>
<xsl:template match="dt">
<fo:block space-before="0.5em">
<xsl:call-template name="set-pagebreak"/>
<xsl:apply-templates/>
</fo:block>
</xsl:template>
<xsl:template match="dd">
<fo:block space-after="0.25em" start-indent="5mm">
<xsl:call-template name="set-pagebreak"/>
<xsl:call-template name="set-pagebreak"/>
<xsl:apply-templates/>
</fo:block>
</xsl:template>
<xsl:template match="table">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="caption">
<fo:caption><fo:block>
<xsl:apply-templates />
</fo:block></fo:caption>
</xsl:template>
<xsl:template match="tbody">
<fo:table space-before="0.5em" space-after="0.5em" table-layout="fixed">
<xsl:for-each select="tr[1]/th|tr[1]/td">
<xsl:variable name="width">
<xsl:call-template name="find-width">
<xsl:with-param name="node" select="."/>
</xsl:call-template>
</xsl:variable>
<fo:table-column>
<xsl:attribute name="column-width">
<xsl:choose>
<xsl:when test="contains($width, '%')"><xsl:value-of
select="floor(number(translate($width,'%','')) div 100
* $bodywidth)"/>cm</xsl:when>
<xsl:otherwise><xsl:value-of
select="$width div 72"/>in</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
</fo:table-column>
</xsl:for-each>
<fo:table-body>
<xsl:apply-templates />
</fo:table-body>
</fo:table>
</xsl:template>
<xsl:template match="tr">
<fo:table-row>
<xsl:if test="@space-before != ''">
<xsl:attribute name="space-before"><xsl:value-of
select="@space-before" /></xsl:attribute>
</xsl:if>
<xsl:if test="@class='graybar'">
<xsl:attribute name="background-color">#ddd</xsl:attribute>
</xsl:if>
<xsl:apply-templates/> </fo:table-row>
</xsl:template>
<xsl:template match="th">
<fo:table-cell font-weight="bold" text-align="center">
<xsl:if test="ancestor::table/@border > 0">
<xsl:attribute name="border-style">solid</xsl:attribute>
<xsl:attribute name="border-width">1pt</xsl:attribute>
</xsl:if>
<fo:block>
<xsl:apply-templates/>
</fo:block></fo:table-cell>
</xsl:template>
<xsl:template match="td">
<fo:table-cell>
<xsl:if test="ancestor::table/@border > 0">
<xsl:attribute name="border-style">solid</xsl:attribute>
<xsl:attribute name="border-width">1pt</xsl:attribute>
</xsl:if>
<fo:block>
<xsl:call-template name="set-alignment"/>
<xsl:apply-templates/>
</fo:block>
</fo:table-cell>
</xsl:template>
<xsl:template match="tt">
<fo:inline font-family="monospace"><xsl:apply-templates/></fo:inline>
</xsl:template>
<xsl:template name="find-width">
<xsl:param name="node"/>
<xsl:choose>
<xsl:when test="@width">
<xsl:value-of select="@width"/>
</xsl:when>
<xsl:when test="@style">
<xsl:value-of select="substring-before(
substring-after(@style, ':'), ';')"/>
</xsl:when>
<xsl:otherwise>0</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="code">
<fo:inline font-family="monospace"><xsl:apply-templates/></fo:inline>
</xsl:template>
<xsl:template match="img">
<fo:external-graphic>
<xsl:attribute name="src">file:<xsl:value-of
select="@src"/></xsl:attribute>
<xsl:attribute name="width"><xsl:value-of
select="@width"/>px</xsl:attribute>
<xsl:attribute name="height"><xsl:value-of
select="@height"/>px</xsl:attribute>
</fo:external-graphic>
</xsl:template>
<xsl:template match="pre">
<fo:block white-space-collapse="false" font-family="monospace" font-size="10pt"><xsl:apply-templates/></fo:block>
</xsl:template>
<xsl:template match="b|strong">
<fo:inline font-weight="bold"><xsl:apply-templates/></fo:inline>
</xsl:template>
<xsl:template match="i|em">
<fo:inline font-style="italic"><xsl:apply-templates/></fo:inline>
</xsl:template>
<xsl:template match="hr">
<fo:block>
<fo:leader
leader-pattern="rule" leader-length.optimum="100%"
rule-style="double" rule-thickness="1pt"/>
</fo:block>
</xsl:template>
<xsl:template match="br">
<fo:block><xsl:text>
</xsl:text></fo:block>
</xsl:template>
<xsl:template match="div[@id='top-navig']"/>
</xsl:stylesheet>