Mercurial > hg > mpdl-group
diff software/eXist/webapp/mpdl/_stuff/futureDev/html2fop.xsl @ 7:5589d865af7a
Erstellung XQL/XSL Applikation
author | Josef Willenborg <jwillenborg@mpiwg-berlin.mpg.de> |
---|---|
date | Tue, 08 Feb 2011 15:16:46 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/software/eXist/webapp/mpdl/_stuff/futureDev/html2fop.xsl Tue Feb 08 15:16:46 2011 +0100 @@ -0,0 +1,1727 @@ +<?xml version="1.0"?> +<xsl:stylesheet + version="1.0" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:fo="http://www.w3.org/1999/XSL/Format" + xmlns:fox="http://xml.apache.org/fop/extensions"> + + <!-- ============================================ + This stylesheet transforms most of the common + HTML elements into XSL formatting objects. + + This version written 1 November 2002 by + Doug Tidwell, dtidwell@us.ibm.com. + + Brought to you by your friends at developerWorks: + ibm.com/developerWorks. + =============================================== --> + + <!-- ============================================ + This variable sets the size of the page. If + it's 'ltr', we an 8.5 x 11 inch page; otherwise, + we use an A4-sized page. 'ltr' is the default. + To change the value, you can make the following + line read select="'A4'", or you can check the + documentation for your XSLT processor to see + how to set variables externally to the style + sheet. (For Xalan, add "-PARAM page-size a4" + to the command.) + =============================================== --> + + <xsl:variable name="page-size" select="'ltr'"/> + + <xsl:template match="html"> + + <!-- ============================================ + Because character entities aren't built into + the XSL-FO vocabulary, they're included here. + =============================================== --> + + <xsl:text disable-output-escaping="yes"> +<!DOCTYPE fo:root [ + <!ENTITY tilde "&#126;"> + <!ENTITY florin "&#131;"> + <!ENTITY elip "&#133;"> + <!ENTITY dag "&#134;"> + <!ENTITY ddag "&#135;"> + <!ENTITY cflex "&#136;"> + <!ENTITY permil "&#137;"> + <!ENTITY uscore "&#138;"> + <!ENTITY OElig "&#140;"> + <!ENTITY lsquo "&#145;"> + <!ENTITY rsquo "&#146;"> + <!ENTITY ldquo "&#147;"> + <!ENTITY rdquo "&#148;"> + <!ENTITY bullet "&#149;"> + <!ENTITY endash "&#150;"> + <!ENTITY emdash "&#151;"> + <!ENTITY trade "&#153;"> + <!ENTITY oelig "&#156;"> + <!ENTITY Yuml "&#159;"> + + <!ENTITY nbsp "&#160;"> + <!ENTITY iexcl "&#161;"> + <!ENTITY cent "&#162;"> + <!ENTITY pound "&#163;"> + <!ENTITY curren "&#164;"> + <!ENTITY yen "&#165;"> + <!ENTITY brvbar "&#166;"> + <!ENTITY sect "&#167;"> + <!ENTITY uml "&#168;"> + <!ENTITY copy "&#169;"> + <!ENTITY ordf "&#170;"> + <!ENTITY laquo "&#171;"> + <!ENTITY not "&#172;"> + <!ENTITY shy "&#173;"> + <!ENTITY reg "&#174;"> + <!ENTITY macr "&#175;"> + <!ENTITY deg "&#176;"> + <!ENTITY plusmn "&#177;"> + <!ENTITY sup2 "&#178;"> + <!ENTITY sup3 "&#179;"> + <!ENTITY acute "&#180;"> + <!ENTITY micro "&#181;"> + <!ENTITY para "&#182;"> + <!ENTITY middot "&#183;"> + <!ENTITY cedil "&#184;"> + <!ENTITY sup1 "&#185;"> + <!ENTITY ordm "&#186;"> + <!ENTITY raquo "&#187;"> + <!ENTITY frac14 "&#188;"> + <!ENTITY frac12 "&#189;"> + <!ENTITY frac34 "&#190;"> + <!ENTITY iquest "&#191;"> + <!ENTITY Agrave "&#192;"> + <!ENTITY Aacute "&#193;"> + <!ENTITY Acirc "&#194;"> + <!ENTITY Atilde "&#195;"> + <!ENTITY Auml "&#196;"> + <!ENTITY Aring "&#197;"> + <!ENTITY AElig "&#198;"> + <!ENTITY Ccedil "&#199;"> + <!ENTITY Egrave "&#200;"> + <!ENTITY Eacute "&#201;"> + <!ENTITY Ecirc "&#202;"> + <!ENTITY Euml "&#203;"> + <!ENTITY Igrave "&#204;"> + <!ENTITY Iacute "&#205;"> + <!ENTITY Icirc "&#206;"> + <!ENTITY Iuml "&#207;"> + <!ENTITY ETH "&#208;"> + <!ENTITY Ntilde "&#209;"> + <!ENTITY Ograve "&#210;"> + <!ENTITY Oacute "&#211;"> + <!ENTITY Ocirc "&#212;"> + <!ENTITY Otilde "&#213;"> + <!ENTITY Ouml "&#214;"> + <!ENTITY times "&#215;"> + <!ENTITY Oslash "&#216;"> + <!ENTITY Ugrave "&#217;"> + <!ENTITY Uacute "&#218;"> + <!ENTITY Ucirc "&#219;"> + <!ENTITY Uuml "&#220;"> + <!ENTITY Yacute "&#221;"> + <!ENTITY THORN "&#222;"> + <!ENTITY szlig "&#223;"> + <!ENTITY agrave "&#224;"> + <!ENTITY aacute "&#225;"> + <!ENTITY acirc "&#226;"> + <!ENTITY atilde "&#227;"> + <!ENTITY auml "&#228;"> + <!ENTITY aring "&#229;"> + <!ENTITY aelig "&#230;"> + <!ENTITY ccedil "&#231;"> + <!ENTITY egrave "&#232;"> + <!ENTITY eacute "&#233;"> + <!ENTITY ecirc "&#234;"> + <!ENTITY euml "&#235;"> + <!ENTITY igrave "&#236;"> + <!ENTITY iacute "&#237;"> + <!ENTITY icirc "&#238;"> + <!ENTITY iuml "&#239;"> + <!ENTITY eth "&#240;"> + <!ENTITY ntilde "&#241;"> + <!ENTITY ograve "&#242;"> + <!ENTITY oacute "&#243;"> + <!ENTITY ocirc "&#244;"> + <!ENTITY otilde "&#245;"> + <!ENTITY ouml "&#246;"> + <!ENTITY oslash "&#248;"> + <!ENTITY ugrave "&#249;"> + <!ENTITY uacute "&#250;"> + <!ENTITY ucirc "&#251;"> + <!ENTITY uuml "&#252;"> + <!ENTITY yacute "&#253;"> + <!ENTITY thorn "&#254;"> + <!ENTITY yuml "&#255;"> +]> + </xsl:text> + + <!-- ============================================ + The XSL-FO section starts here.... + =============================================== --> + + <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" + xmlns:fox="http://xml.apache.org/fop/extensions"> + + <!-- ============================================ + Define the page layouts. There are two sets of + three page mastters here; we use one set for + letter-sized paper, the other set for A4. + =============================================== --> + + <fo:layout-master-set> + <xsl:choose> + <xsl:when test="$page-size='ltr'"> + <fo:simple-page-master master-name="first" + page-height="11in" page-width="8.5in" + margin-right="72pt" margin-left="72pt" + margin-bottom="36pt" margin-top="72pt"> + <fo:region-body margin-bottom="50pt"/> + <fo:region-after region-name="ra-right" + extent="25pt"/> + </fo:simple-page-master> + + <fo:simple-page-master master-name="left" + page-height="11in" page-width="8.5in" + margin-right="72pt" margin-left="72pt" + margin-bottom="36pt" margin-top="36pt"> + <fo:region-before region-name="rb-left" + extent="25pt"/> + <fo:region-body margin-top="50pt" + margin-bottom="50pt"/> + <fo:region-after region-name="ra-left" + extent="25pt"/> + </fo:simple-page-master> + + <fo:simple-page-master master-name="right" + page-height="11in" page-width="8.5in" + margin-right="72pt" margin-left="72pt" + margin-bottom="36pt" margin-top="36pt"> + <fo:region-before region-name="rb-right" + extent="25pt"/> + <fo:region-body margin-top="50pt" + margin-bottom="50pt"/> + <fo:region-after region-name="ra-right" + extent="25pt"/> + </fo:simple-page-master> + </xsl:when> + + <!-- ============================================ + Page layouts for A4-sized paper + =============================================== --> + + <xsl:otherwise> + <fo:simple-page-master master-name="first" + page-height="29.7cm" page-width="21cm" + margin-right="72pt" margin-left="72pt" + margin-bottom="36pt" margin-top="72pt"> + <fo:region-body margin-top="1.5cm" + margin-bottom="1.5cm"/> + <fo:region-after region-name="ra-right" + extent="1cm"/> + </fo:simple-page-master> + + <fo:simple-page-master master-name="left" + page-height="29.7cm" page-width="21cm" + margin-right="72pt" margin-left="72pt" + margin-bottom="36pt" margin-top="36pt"> + <fo:region-before region-name="rb-left" + extent="3cm"/> + <fo:region-body margin-top="1.5cm" + margin-bottom="1.5cm"/> + <fo:region-after region-name="ra-left" + extent="1cm"/> + </fo:simple-page-master> + + <fo:simple-page-master master-name="right" + page-height="29.7cm" page-width="21cm" + margin-right="72pt" margin-left="72pt" + margin-bottom="36pt" margin-top="36pt"> + <fo:region-before region-name="rb-right" + extent="3cm"/> + <fo:region-body margin-top="1.5cm" + margin-bottom="1.5cm"/> + <fo:region-after region-name="ra-right" + extent="1cm"/> + </fo:simple-page-master> + </xsl:otherwise> + </xsl:choose> + + <!-- ============================================ + Now we define how we use the page layouts. One + is for the first page, one is for the even- + numbered pages, and one is for odd-numbered pages. + =============================================== --> + + <fo:page-sequence-master master-name="standard"> + <fo:repeatable-page-master-alternatives> + <fo:conditional-page-master-reference + master-reference="first" + page-position="first"/> + <fo:conditional-page-master-reference + master-reference="left" + odd-or-even="even"/> + <fo:conditional-page-master-reference + master-reference="right" + odd-or-even="odd"/> + </fo:repeatable-page-master-alternatives> + </fo:page-sequence-master> + + </fo:layout-master-set> + + <!-- ============================================ + Now that we've defined all of the page layouts, + we generate the bookmarks for the PDF file. + =============================================== --> + + <xsl:call-template name="generate-bookmarks"/> + + <!-- ============================================ + This is where the actual content of the document + starts. + =============================================== --> + + <fo:page-sequence master-reference="standard"> + + <!-- ============================================ + We define the static content for the headers + and footers of the various page layouts first. + =============================================== --> + + <fo:static-content flow-name="rb-right"> + <fo:block font-size="10pt" text-align-last="end"> + <fo:table table-layout="fixed"> + <fo:table-column column-width="396pt"/> + <fo:table-column column-width="72pt"/> + <fo:table-body> + <fo:table-row> + <fo:table-cell> + <fo:block text-align="start"> + developerWorks loves you! + </fo:block> + </fo:table-cell> + <fo:table-cell> + <fo:block text-align="end" font-weight="bold" + font-family="monospace"> + ibm.com/developerWorks + </fo:block> + </fo:table-cell> + </fo:table-row> + </fo:table-body> + </fo:table> + </fo:block> + </fo:static-content> + <fo:static-content flow-name="ra-right"> + <fo:block font-size="10pt" text-align-last="end"> + <fo:table table-layout="fixed"> + <fo:table-column column-width="396pt"/> + <fo:table-column column-width="72pt"/> + <fo:table-body> + <fo:table-row> + <fo:table-cell> + <fo:block text-align="start"> + <xsl:value-of select="/html/head/title"/> + </fo:block> + </fo:table-cell> + <fo:table-cell> + <fo:block text-align="end">Page + <fo:page-number/> of + <fo:page-number-citation + ref-id="TheVeryLastPage"/> + </fo:block> + </fo:table-cell> + </fo:table-row> + </fo:table-body> + </fo:table> + </fo:block> + </fo:static-content> + <fo:static-content flow-name="rb-left"> + <fo:block font-size="10pt" text-align-last="end"> + <fo:table table-layout="fixed"> + <fo:table-column column-width="72pt"/> + <fo:table-column column-width="396pt"/> + <fo:table-body> + <fo:table-row> + <fo:table-cell> + <fo:block text-align="start" font-weight="bold" + font-family="monospace"> + ibm.com/developerWorks + </fo:block> + </fo:table-cell> + <fo:table-cell> + <fo:block text-align="end"> + developerWorks loves you! + </fo:block> + </fo:table-cell> + </fo:table-row> + </fo:table-body> + </fo:table> + </fo:block> + </fo:static-content> + <fo:static-content flow-name="ra-left"> + <fo:block font-size="10pt" text-align-last="end"> + <fo:table table-layout="fixed"> + <fo:table-column column-width="72pt"/> + <fo:table-column column-width="396pt"/> + <fo:table-body> + <fo:table-row> + <fo:table-cell> + <fo:block text-align="start">Page + <fo:page-number/> + of <fo:page-number-citation + ref-id="TheVeryLastPage"/> + </fo:block> + </fo:table-cell> + <fo:table-cell> + <fo:block text-align="end"> + <xsl:value-of select="/html/head/title"/> + </fo:block> + </fo:table-cell> + </fo:table-row> + </fo:table-body> + </fo:table> + </fo:block> + </fo:static-content> + + <xsl:apply-templates select="body"/> + </fo:page-sequence> + </fo:root> + </xsl:template> + + <!-- ============================================ + Templates for individual HTML elements begin + here. + =============================================== --> + + <!-- ============================================ + Processing for the anchor tag is complex. First + of all, if this is a named anchor, we write an empty + <fo:block> with the appropriate id. (In the special + case that the next element is an <h1>, we ignore + the element altogether and put the id on the <h1>.) + Next, if this is a regular anchor and the href + starts with a hash mark (#), we create a link with + an internal-destination. Otherwise, we create a + link with an external destination. + =============================================== --> + + <xsl:template match="a"> + <xsl:choose> + <xsl:when test="@name"> + <xsl:if test="not(name(following-sibling::*[1]) = 'h1')"> + <fo:block line-height="0pt" space-after="0pt" + font-size="0pt" id="{@name}"/> + </xsl:if> + </xsl:when> + <xsl:when test="@href"> + <fo:basic-link color="blue"> + <xsl:choose> + <xsl:when test="starts-with(@href, '#')"> + <xsl:attribute name="internal-destination"> + <xsl:value-of select="substring(@href, 2)"/> + </xsl:attribute> + </xsl:when> + <xsl:otherwise> + <xsl:attribute name="external-destination"> + <xsl:value-of select="@href"/> + </xsl:attribute> + </xsl:otherwise> + </xsl:choose> + <xsl:apply-templates select="*|text()"/> + </fo:basic-link> + <xsl:if test="starts-with(@href, '#')"> + <xsl:text> on page </xsl:text> + <fo:page-number-citation ref-id="{substring(@href, 2)}"/> + </xsl:if> + </xsl:when> + </xsl:choose> + </xsl:template> + + <!-- ============================================ + We render an address element in italics. + =============================================== --> + + <xsl:template match="address"> + <fo:block font-style="italic" space-after="12pt"> + <xsl:apply-templates select="*|text()"/> + </fo:block> + </xsl:template> + + <!-- ============================================ + For bold elements, we just change the font-weight. + =============================================== --> + + <xsl:template match="b"> + <fo:inline font-weight="bold"> + <xsl:apply-templates select="*|text()"/> + </fo:inline> + </xsl:template> + + <!-- ============================================ + The big element is handled with a relative + font size. That means a <big> element inside + another <big> element will be even bigger, just + as it is in HTML. + =============================================== --> + + <xsl:template match="big"> + <fo:inline font-size="120%"> + <xsl:apply-templates select="*|text()"/> + </fo:inline> + </xsl:template> + + <!-- ============================================ + A blockquote is indented on both sides. + =============================================== --> + + <xsl:template match="blockquote"> + <fo:block start-indent="1.5cm" end-indent="1.5cm" + space-after="12pt"> + <xsl:apply-templates select="*|text()"/> + </fo:block> + </xsl:template> + + <!-- ============================================ + The HTML <body> element contains everything in + the main part of the document. This is analogous + to the <fo:flow flow-name="xsl-region-body"> + element, so we put the main document processing here. + =============================================== --> + + <xsl:template match="body"> + + <!-- ============================================ + Start generating the content for the main page + area (xsl-region-body). + =============================================== --> + + <fo:flow flow-name="xsl-region-body"> + <xsl:apply-templates select="/html/head/title"/> + <fo:block space-after="12pt" line-height="17pt" + font-size="14pt" text-align="center"> + developerWorks loves you! + </fo:block> + <fo:block space-after="24pt" line-height="17pt" + font-size="14pt" text-align="center" font-weight="bold" + font-family="monospace"> + ibm.com/developerWorks + </fo:block> + + <!-- ============================================ + Now we call the template to build the table + of contents. + =============================================== --> + + <xsl:call-template name="toc"/> + + <!-- ============================================ + This one line of code processes everything in + the body of the document. The template that + processes the <body> element in turn processes + everything that's inside it. + =============================================== --> + + <xsl:apply-templates select="*|text()"/> + + <!-- ============================================ + We put an ID at the end of the document so we + can do "Page x of y" numbering. + =============================================== --> + <fo:block id="TheVeryLastPage" font-size="0pt" + line-height="0pt" space-after="0pt"/> + + </fo:flow> + </xsl:template> + + <!-- ============================================ + We handle a break element by inserting an + empty <fo:block>. + =============================================== --> + + <xsl:template match="br"> + <fo:block> </fo:block> + </xsl:template> + + <!-- ============================================ + We're handling <center> as a block element; if + you use it, it creates a new paragraph that's + centered on the page. + =============================================== --> + + <xsl:template match="center"> + <fo:block text-align="center"> + <xsl:apply-templates select="*|text()"/> + </fo:block> + </xsl:template> + + <!-- ============================================ + The <cite> element is rendered in italics, + unless it's inside an italic (<i>) element. + We use the parent axis to check this. + =============================================== --> + + <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> + + <!-- ============================================ + We render <code> inline in a monospaced font. + =============================================== --> + + <xsl:template match="code"> + <fo:inline font-family="monospace"> + <xsl:apply-templates select="*|text()"/> + </fo:inline> + </xsl:template> + + <!-- ============================================ + We don't do anything with the <dl> element, we + just handle the elements it contains. Notice + that we're ignoring any text that appears + in the <dl> itself; I'm not sure if that's + the right call. + =============================================== --> + + <xsl:template match="dl"> + <xsl:apply-templates select="*"/> + </xsl:template> + + <!-- ============================================ + A definition term is rendered in bold. We + specify keep-with-next here, although it doesn't + always work with FOP. + =============================================== --> + + <xsl:template match="dt"> + <fo:block font-weight="bold" space-after="2pt" + keep-with-next="always"> + <xsl:apply-templates select="*|text()"/> + </fo:block> + </xsl:template> + + <!-- ============================================ + We handle each <dd> element as an indented block + beneath the defined term. If the following + element is another <dd>, that means it's another + definition for the same term. In that case, + we don't put as much vertical space after the + block. + =============================================== --> + + <xsl:template match="dd"> + <fo:block start-indent="1cm"> + <xsl:attribute name="space-after"> + <xsl:choose> + <xsl:when test="name(following::*[1]) = 'dd'"> + <xsl:text>3pt</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:text>12pt</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:attribute> + <xsl:apply-templates select="*|text()"/> + </fo:block> + </xsl:template> + + <!-- ============================================ + The HTML <em> element is typically rendered in + italics. + =============================================== --> + + <xsl:template match="em"> + <fo:inline font-style="italic"> + <xsl:apply-templates select="*|text()"/> + </fo:inline> + </xsl:template> + + <!-- ============================================ + For the <font> element, we handle the color, + face, and size attributes. Color will work if + it's one of the twelve colors supported by XSL-FO + or it's a hex value like x0033ff. (In other words, + if you tell FOP to set the color to PapayaWhip, + you're out of luck.) The face attribute will + work if FOP supports it. (There are ways to add + fonts to FOP, see the FOP documentation for more + info.) Size is supported for values like + size="14pt", size="3", and size="+3". + =============================================== --> + + <xsl:template match="font"> + <xsl:variable name="color"> + <xsl:choose> + <xsl:when test="@color"> + <xsl:value-of select="@color"/> + </xsl:when> + <xsl:otherwise> + <xsl:text>black</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:variable name="face"> + <xsl:choose> + <xsl:when test="@face"> + <xsl:value-of select="@face"/> + </xsl:when> + <xsl:otherwise> + <xsl:text>sans-serif</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:variable name="size"> + <xsl:choose> + <xsl:when test="@size"> + <xsl:choose> + <xsl:when test="contains(@size, 'pt')"> + <xsl:text>@size</xsl:text> + </xsl:when> + <xsl:when test="@size = '+1'"> + <xsl:text>110%</xsl:text> + </xsl:when> + <xsl:when test="@size = '+2'"> + <xsl:text>120%</xsl:text> + </xsl:when> + <xsl:when test="@size = '+3'"> + <xsl:text>130%</xsl:text> + </xsl:when> + <xsl:when test="@size = '+4'"> + <xsl:text>140%</xsl:text> + </xsl:when> + <xsl:when test="@size = '+5'"> + <xsl:text>150%</xsl:text> + </xsl:when> + <xsl:when test="@size = '+6'"> + <xsl:text>175%</xsl:text> + </xsl:when> + <xsl:when test="@size = '+7'"> + <xsl:text>200%</xsl:text> + </xsl:when> + <xsl:when test="@size = '-1'"> + <xsl:text>90%</xsl:text> + </xsl:when> + <xsl:when test="@size = '-2'"> + <xsl:text>80%</xsl:text> + </xsl:when> + <xsl:when test="@size = '-3'"> + <xsl:text>70%</xsl:text> + </xsl:when> + <xsl:when test="@size = '-4'"> + <xsl:text>60%</xsl:text> + </xsl:when> + <xsl:when test="@size = '-5'"> + <xsl:text>50%</xsl:text> + </xsl:when> + <xsl:when test="@size = '-6'"> + <xsl:text>40%</xsl:text> + </xsl:when> + <xsl:when test="@size = '-7'"> + <xsl:text>30%</xsl:text> + </xsl:when> + <xsl:when test="@size = '1'"> + <xsl:text>8pt</xsl:text> + </xsl:when> + <xsl:when test="@size = '2'"> + <xsl:text>10pt</xsl:text> + </xsl:when> + <xsl:when test="@size = '3'"> + <xsl:text>12pt</xsl:text> + </xsl:when> + <xsl:when test="@size = '4'"> + <xsl:text>14pt</xsl:text> + </xsl:when> + <xsl:when test="@size = '5'"> + <xsl:text>18pt</xsl:text> + </xsl:when> + <xsl:when test="@size = '6'"> + <xsl:text>24pt</xsl:text> + </xsl:when> + <xsl:when test="@size = '7'"> + <xsl:text>36pt</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:text>12pt</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise> + <xsl:text>12pt</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <fo:inline font-size="{$size}" font-family="{$face}" + color="{$color}"> + <xsl:apply-templates select="*|text()"/> + </fo:inline> + </xsl:template> + + <!-- ============================================ + We render the <h1> by putting a horizontal rule + and a page break before it. We also process + the id attribute; if the <h1> tag has one, we + use it. If not, we see if the preceding element + is a named anchor (<a name="x"/>). If there is + a named anchor before the <h1>, we use the name + of the anchor point as the id. + =============================================== --> + + <xsl:template match="h1"> + <fo:block break-before="page"> + <fo:leader leader-pattern="rule"/> + </fo:block> + <fo:block font-size="28pt" line-height="32pt" + keep-with-next="always" + space-after="22pt" font-family="serif"> + <xsl:attribute name="id"> + <xsl:choose> + <xsl:when test="@id"> + <xsl:value-of select="@id"/> + </xsl:when> + <xsl:when test="name(preceding-sibling::*[1]) = 'a' and + preceding-sibling::*[1][@name]"> + <xsl:value-of select="preceding-sibling::*[1]/@name"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="generate-id()"/> + </xsl:otherwise> + </xsl:choose> + </xsl:attribute> + <xsl:apply-templates select="*|text()"/> + </fo:block> + </xsl:template> + + <!-- ============================================ + <h2> is in a slightly smaller font than an <h1>, + and it doesn't have a page break or a line. + =============================================== --> + + <xsl:template match="h2"> + <fo:block font-size="24pt" line-height="28pt" + keep-with-next="always" space-after="18pt" + font-family="serif"> + <xsl:attribute name="id"> + <xsl:choose> + <xsl:when test="@id"> + <xsl:value-of select="@id"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="generate-id()"/> + </xsl:otherwise> + </xsl:choose> + </xsl:attribute> + <xsl:apply-templates select="*|text()"/> + </fo:block> + </xsl:template> + + <!-- ============================================ + <h3> is slightly smaller than <h2>. + =============================================== --> + + <xsl:template match="h3"> + <fo:block font-size="21pt" line-height="24pt" + keep-with-next="always" space-after="14pt" + font-family="serif"> + <xsl:attribute name="id"> + <xsl:choose> + <xsl:when test="@id"> + <xsl:value-of select="@id"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="generate-id()"/> + </xsl:otherwise> + </xsl:choose> + </xsl:attribute> + <xsl:apply-templates select="*|text()"/> + </fo:block> + </xsl:template> + + <!-- ============================================ + <h4> is smaller than <h3>. For the bookmarks + and table of contents, <h4> is the lowest level + we include. + =============================================== --> + + <xsl:template match="h4"> + <fo:block font-size="18pt" line-height="21pt" + keep-with-next="always" space-after="12pt" + font-family="serif"> + <xsl:attribute name="id"> + <xsl:choose> + <xsl:when test="@id"> + <xsl:value-of select="@id"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="generate-id()"/> + </xsl:otherwise> + </xsl:choose> + </xsl:attribute> + <xsl:apply-templates select="*|text()"/> + </fo:block> + </xsl:template> + + <!-- ============================================ + <h5> is pretty small, and is underlined to + help it stand out. + =============================================== --> + + <xsl:template match="h5"> + <fo:block font-size="16pt" line-height="19pt" + keep-with-next="always" space-after="12pt" + font-family="serif" text-decoration="underline"> + <xsl:attribute name="id"> + <xsl:choose> + <xsl:when test="@id"> + <xsl:value-of select="@id"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="generate-id()"/> + </xsl:otherwise> + </xsl:choose> + </xsl:attribute> + <xsl:apply-templates select="*|text()"/> + </fo:block> + </xsl:template> + + <!-- ============================================ + <h6> is the smallest heading of all, and is + underlined and italicized. + =============================================== --> + + <xsl:template match="h6"> + <fo:block font-size="14pt" line-height="17pt" + keep-with-next="always" space-after="12pt" + font-family="serif" font-style="italic" + text-decoration="underline"> + <xsl:attribute name="id"> + <xsl:choose> + <xsl:when test="@id"> + <xsl:value-of select="@id"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="generate-id()"/> + </xsl:otherwise> + </xsl:choose> + </xsl:attribute> + <xsl:apply-templates select="*|text()"/> + </fo:block> + </xsl:template> + + <!-- ============================================ + We render an <hr> with a leader. Because <hr> + is empty, we don't have to process any child + elements. + =============================================== --> + + <xsl:template match="hr"> + <fo:block> + <fo:leader leader-pattern="rule"/> + </fo:block> + </xsl:template> + + <!-- ============================================ + Italics. You can't get much simpler than that. + =============================================== --> + + <xsl:template match="i"> + <fo:inline font-style="italic"> + <xsl:apply-templates select="*|text()"/> + </fo:inline> + </xsl:template> + + <!-- ============================================ + For the <img> element, we use the src attribute + as it comes from HTML. We also check for any + width and height attributes. If those attributes + are there, we try to use them; height="300px" is + used as-is, while height="300" is converted to + the value "300px". + =============================================== --> + + <xsl:template match="img"> + <fo:block space-after="12pt"> + <fo:external-graphic src="{@src}"> + <xsl:if test="@width"> + <xsl:attribute name="width"> + <xsl:choose> + <xsl:when test="contains(@width, 'px')"> + <xsl:value-of select="@width"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="concat(@width, 'px')"/> + </xsl:otherwise> + </xsl:choose> + </xsl:attribute> + </xsl:if> + <xsl:if test="@height"> + <xsl:attribute name="height"> + <xsl:choose> + <xsl:when test="contains(@height, 'px')"> + <xsl:value-of select="@height"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="concat(@height, 'px')"/> + </xsl:otherwise> + </xsl:choose> + </xsl:attribute> + </xsl:if> + </fo:external-graphic> + </fo:block> + </xsl:template> + + <!-- ============================================ + The <kbd> element is in a slightly larger + monospaced text. + =============================================== --> + + <xsl:template match="kbd"> + <fo:inline font-family="monospace" font-size="110%"> + <xsl:apply-templates select="*|text()"/> + </fo:inline> + </xsl:template> + + <!-- ============================================ + We handle the <li> elements under the <ol> and + <ul> elements, so there's no <li> template here. + =============================================== --> + + <!-- ============================================ + For the <nobr> element, we simply turn off the + wrap-option. + =============================================== --> + + <xsl:template match="nobr"> + <fo:inline wrap-option="no-wrap"> + <xsl:apply-templates select="*|text()"/> + </fo:inline> + </xsl:template> + + <!-- ============================================ + We handle an ordered list with two complications: + If the list appears inside another list (either + an <ol> or <ul>), we don't put any vertical space + after it. The other issue is that we indent the + list according to how deeply nested the list is. + =============================================== --> + + <xsl:template match="ol"> + <fo:list-block provisional-distance-between-starts="1cm" + provisional-label-separation="0.5cm"> + <xsl:attribute name="space-after"> + <xsl:choose> + <xsl:when test="ancestor::ul or ancestor::ol"> + <xsl:text>0pt</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:text>12pt</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:attribute> + <xsl:attribute name="start-indent"> + <xsl:variable name="ancestors"> + <xsl:choose> + <xsl:when test="count(ancestor::ol) or count(ancestor::ul)"> + <xsl:value-of select="1 + + (count(ancestor::ol) + + count(ancestor::ul)) * + 1.25"/> + </xsl:when> + <xsl:otherwise> + <xsl:text>1</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:value-of select="concat($ancestors, 'cm')"/> + </xsl:attribute> + <xsl:apply-templates select="*"/> + </fo:list-block> + </xsl:template> + + <!-- ============================================ + When we handle items in an ordered list, we need + to check if the list has a start attribute. If + it does, we change the starting number accordingly. + Once we've figured out where to start counting, + we check the type attribute to see what format + the numbers should use. + =============================================== --> + + <xsl:template match="ol/li"> + <fo:list-item> + <fo:list-item-label end-indent="label-end()"> + <fo:block> + <xsl:variable name="value-attr"> + <xsl:choose> + <xsl:when test="../@start"> + <xsl:number value="position() + ../@start - 1"/> + </xsl:when> + <xsl:otherwise> + <xsl:number value="position()"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:choose> + <xsl:when test="../@type='i'"> + <xsl:number value="$value-attr" format="i. "/> + </xsl:when> + <xsl:when test="../@type='I'"> + <xsl:number value="$value-attr" format="I. "/> + </xsl:when> + <xsl:when test="../@type='a'"> + <xsl:number value="$value-attr" format="a. "/> + </xsl:when> + <xsl:when test="../@type='A'"> + <xsl:number value="$value-attr" format="A. "/> + </xsl:when> + <xsl:otherwise> + <xsl:number value="$value-attr" 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 select="*|text()"/> + </fo:block> + </fo:list-item-body> + </fo:list-item> + </xsl:template> + + <!-- ============================================ + Your basic paragraph. + =============================================== --> + + <xsl:template match="p"> + <fo:block font-size="12pt" line-height="15pt" + space-after="12pt"> + <xsl:apply-templates select="*|text()"/> + </fo:block> + </xsl:template> + + <!-- ============================================ + Preformatted text is rendered in a monospaced + font. We also have to set the wrap-option + and white-space-collapse properties. + =============================================== --> + + <xsl:template match="pre"> + <fo:block font-family="monospace" + white-space-collapse="false" wrap-option="no-wrap"> + <xsl:apply-templates select="*|text()"/> + </fo:block> + </xsl:template> + + <!-- ============================================ + Sample text is rendered in a slightly larger + monospaced font. + =============================================== --> + + <xsl:template match="samp"> + <fo:inline font-family="monospace" font-size="110%"> + <xsl:apply-templates select="*|text()"/> + </fo:inline> + </xsl:template> + + <!-- ============================================ + The <small> element is rendered with a relative + font size. That means putting one <small> + element inside another creates really small + text. + =============================================== --> + + <xsl:template match="small"> + <fo:inline font-size="80%"> + <xsl:apply-templates select="*|text()"/> + </fo:inline> + </xsl:template> + + <!-- ============================================ + For strikethrough text, we use the text-decoration + property. + =============================================== --> + + <xsl:template match="strike"> + <fo:inline text-decoration="line-through"> + <xsl:apply-templates select="*|text()"/> + </fo:inline> + </xsl:template> + + <!-- ============================================ + Strongly emphasized text is simply rendered + in bold. + =============================================== --> + + <xsl:template match="strong"> + <fo:inline font-weight="bold"> + <xsl:apply-templates select="*|text()"/> + </fo:inline> + </xsl:template> + + <!-- ============================================ + For subscript text, we use the vertical-align + property and decrease the font size. + =============================================== --> + + <xsl:template match="sub"> + <fo:inline vertical-align="sub" font-size="75%"> + <xsl:apply-templates select="*|text()"/> + </fo:inline> + </xsl:template> + + <!-- ============================================ + Superscript text changes the vertical-align + property also, and uses a smaller font. + =============================================== --> + + <xsl:template match="sup"> + <fo:inline vertical-align="super" font-size="75%"> + <xsl:apply-templates select="*|text()"/> + </fo:inline> + </xsl:template> + + <!-- ============================================ + Tables are a hassle. The main problem we have + is converting the cols attribute into some + number of <fo:table-column> elements. We do + this with a named template called build-columns. + Once we've processed the cols attribute, we + invoke all of the templates for the children + of this element. + =============================================== --> + + <xsl:template match="table"> + <fo:table table-layout="fixed"> + <xsl:choose> + <xsl:when test="@cols"> + <xsl:call-template name="build-columns"> + <xsl:with-param name="cols" + select="concat(@cols, ' ')"/> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <fo:table-column column-width="200pt"/> + </xsl:otherwise> + </xsl:choose> + <fo:table-body> + <xsl:apply-templates select="*"/> + </fo:table-body> + </fo:table> + </xsl:template> + + <!-- ============================================ + For a table cell, we put everything inside a + <fo:table-cell> element. We set the padding + property correctly, then we set the border + style. For the border style, we look to see if + any of the ancestor elements we care about + specified a solid border. Next, we check for the + rowspan, colspan, and align attributes. Notice + that for align, we check this element, then go + up the ancestor chain until we find the <table> + element or we find something that specifies the + alignment. + =============================================== --> + + <xsl:template match="td"> + <fo:table-cell + padding-start="3pt" padding-end="3pt" + padding-before="3pt" padding-after="3pt"> + <xsl:if test="@colspan"> + <xsl:attribute name="number-columns-spanned"> + <xsl:value-of select="@colspan"/> + </xsl:attribute> + </xsl:if> + <xsl:if test="@rowspan"> + <xsl:attribute name="number-rows-spanned"> + <xsl:value-of select="@rowspan"/> + </xsl:attribute> + </xsl:if> + <xsl:if test="@border='1' or + ancestor::tr[@border='1'] or + ancestor::thead[@border='1'] or + ancestor::table[@border='1']"> + <xsl:attribute name="border-style"> + <xsl:text>solid</xsl:text> + </xsl:attribute> + <xsl:attribute name="border-color"> + <xsl:text>black</xsl:text> + </xsl:attribute> + <xsl:attribute name="border-width"> + <xsl:text>1pt</xsl:text> + </xsl:attribute> + </xsl:if> + <xsl:variable name="align"> + <xsl:choose> + <xsl:when test="@align"> + <xsl:choose> + <xsl:when test="@align='center'"> + <xsl:text>center</xsl:text> + </xsl:when> + <xsl:when test="@align='right'"> + <xsl:text>end</xsl:text> + </xsl:when> + <xsl:when test="@align='justify'"> + <xsl:text>justify</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:text>start</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:when test="ancestor::tr[@align]"> + <xsl:choose> + <xsl:when test="ancestor::tr/@align='center'"> + <xsl:text>center</xsl:text> + </xsl:when> + <xsl:when test="ancestor::tr/@align='right'"> + <xsl:text>end</xsl:text> + </xsl:when> + <xsl:when test="ancestor::tr/@align='justify'"> + <xsl:text>justify</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:text>start</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:when test="ancestor::thead"> + <xsl:text>center</xsl:text> + </xsl:when> + <xsl:when test="ancestor::table[@align]"> + <xsl:choose> + <xsl:when test="ancestor::table/@align='center'"> + <xsl:text>center</xsl:text> + </xsl:when> + <xsl:when test="ancestor::table/@align='right'"> + <xsl:text>end</xsl:text> + </xsl:when> + <xsl:when test="ancestor::table/@align='justify'"> + <xsl:text>justify</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:text>start</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise> + <xsl:text>start</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <fo:block text-align="{$align}"> + <xsl:apply-templates select="*|text()"/> + </fo:block> + </fo:table-cell> + </xsl:template> + + <!-- ============================================ + The rarely-used <tfoot> element contains some + number of <tr> elements; we just invoke the + template for <tr> here. + =============================================== --> + + <xsl:template match="tfoot"> + <xsl:apply-templates select="tr"/> + </xsl:template> + + <!-- ============================================ + If there's a <th> element, we process it just + like a normal <td>, except the font-weight is + always bold and the text-align is always center. + =============================================== --> + + <xsl:template match="th"> + <fo:table-cell + padding-start="3pt" padding-end="3pt" + padding-before="3pt" padding-after="3pt"> + <xsl:if test="@border='1' or + ancestor::tr[@border='1'] or + ancestor::table[@border='1']"> + <xsl:attribute name="border-style"> + <xsl:text>solid</xsl:text> + </xsl:attribute> + <xsl:attribute name="border-color"> + <xsl:text>black</xsl:text> + </xsl:attribute> + <xsl:attribute name="border-width"> + <xsl:text>1pt</xsl:text> + </xsl:attribute> + </xsl:if> + <fo:block font-weight="bold" text-align="center"> + <xsl:apply-templates select="*|text()"/> + </fo:block> + </fo:table-cell> + </xsl:template> + + <!-- ============================================ + Just like <tfoot>, the rarely-used <thead> element + contains some number of table rows. We just + invoke the template for <tr> here. + =============================================== --> + + <xsl:template match="thead"> + <xsl:apply-templates select="tr"/> + </xsl:template> + + <!-- ============================================ + The title of the document is rendered in a large + bold font, centered on the page. This is the + <title> element in the <head> in <html>. + =============================================== --> + + <xsl:template match="title"> + <fo:block space-after="18pt" line-height="27pt" + font-size="24pt" font-weight="bold" text-align="center"> + <xsl:apply-templates select="*|text()"/> + </fo:block> + </xsl:template> + + <!-- ============================================ + For an HTML table row, we create an XSL-FO table + row, then invoke the templates for everything + inside it. + =============================================== --> + + <xsl:template match="tr"> + <fo:table-row> + <xsl:apply-templates select="*|text()"/> + </fo:table-row> + </xsl:template> + + <!-- ============================================ + Teletype text is rendered in a monospaced font. + =============================================== --> + + <xsl:template match="tt"> + <fo:inline font-family="monospace"> + <xsl:apply-templates select="*|text()"/> + </fo:inline> + </xsl:template> + + <!-- ============================================ + For underlined text, we use the text-decoration + property. + =============================================== --> + + <xsl:template match="u"> + <fo:inline text-decoration="underline"> + <xsl:apply-templates select="*|text()"/> + </fo:inline> + </xsl:template> + + <!-- ============================================ + The unordered list is pretty straightforward; + the only complication is calculating the space- + after and start-indent properties. If this + list is inside another list, we don't put any + space after this one, and we calculate the + indentation based on the nesting level of this + list. + =============================================== --> + + <xsl:template match="ul"> + <fo:list-block provisional-distance-between-starts="1cm" + provisional-label-separation="0.5cm"> + <xsl:attribute name="space-after"> + <xsl:choose> + <xsl:when test="ancestor::ul or ancestor::ol"> + <xsl:text>0pt</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:text>12pt</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:attribute> + <xsl:attribute name="start-indent"> + <xsl:variable name="ancestors"> + <xsl:choose> + <xsl:when test="count(ancestor::ol) or count(ancestor::ul)"> + <xsl:value-of select="1 + + (count(ancestor::ol) + + count(ancestor::ul)) * + 1.25"/> + </xsl:when> + <xsl:otherwise> + <xsl:text>1</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:value-of select="concat($ancestors, 'cm')"/> + </xsl:attribute> + <xsl:apply-templates select="*"/> + </fo:list-block> + </xsl:template> + + <!-- ============================================ + List items inside unordered lists are easy; we + just have to use the correct Unicode character + for the bullet. + =============================================== --> + + <xsl:template match="ul/li"> + <fo:list-item> + <fo:list-item-label end-indent="label-end()"> + <fo:block>•</fo:block> + </fo:list-item-label> + <fo:list-item-body start-indent="body-start()"> + <fo:block> + <xsl:apply-templates select="*|text()"/> + </fo:block> + </fo:list-item-body> + </fo:list-item> + </xsl:template> + + <!-- ============================================ + The <var> element is rendered in italics. + =============================================== --> + + <xsl:template match="var"> + <fo:inline font-style="italic"> + <xsl:apply-templates select="*|text()"/> + </fo:inline> + </xsl:template> + + <!-- ============================================ + Named templates + =============================================== --> + + <!-- ============================================ + This template creates the table of contents. + It indents each entry according to the heading + level (<h1> isn't indented, <h2> is indented + 1 cm, etc.). We insert the title of each + section as a link, put a leader of dots, then + the page number. Notice that we generate an + id for the heading if it doesn't have one + already; this is done with the XSLT generate-id() + function. + =============================================== --> + + <xsl:template name="toc"> + <fo:block> + <fo:leader leader-pattern="rule" space-after="18pt"/> + </fo:block> + <fo:block space-after="12pt" id="TableOfContents" + line-height="21pt" font-size="18pt" text-align="start"> + Table of Contents + </fo:block> + <fo:block line-height="11pt" font-size="8pt" + space-after="6pt"> + If you're viewing this document online, you can + click any of the topics below to link directly to + that section. + </fo:block> + <xsl:for-each select="/html/body//h1 | + /html/body//h2 | + /html/body//h3 | + /html/body//h4"> + <fo:block text-align-last="justify" line-height="17pt" + font-size="14pt" space-after="3pt" text-align="start" + text-indent="-1cm"> + <xsl:attribute name="start-indent"> + <xsl:choose> + <xsl:when test="name() = 'h1'"> + <xsl:text>1cm</xsl:text> + </xsl:when> + <xsl:when test="name() = 'h2'"> + <xsl:text>1.5cm</xsl:text> + </xsl:when> + <xsl:when test="name() = 'h3'"> + <xsl:text>2cm</xsl:text> + </xsl:when> + <xsl:when test="name() = 'h4'"> + <xsl:text>2.5cm</xsl:text> + </xsl:when> + </xsl:choose> + </xsl:attribute> + <fo:basic-link color="blue"> + <xsl:attribute name="internal-destination"> + <xsl:choose> + <xsl:when test="@id"> + <xsl:value-of select="@id"/> + </xsl:when> + <xsl:when test="name(preceding-sibling::*[1]) = 'a' and + preceding-sibling::*[1][@name]"> + <xsl:value-of select="preceding-sibling::*[1]/@name"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="generate-id()"/> + </xsl:otherwise> + </xsl:choose> + </xsl:attribute> + <xsl:apply-templates select="*|text()"/> + </fo:basic-link> + <fo:leader leader-pattern="dots" + leader-pattern-width="5pt"/> + <fo:page-number-citation> + <xsl:attribute name="ref-id"> + <xsl:choose> + <xsl:when test="@id"> + <xsl:value-of select="@id"/> + </xsl:when> + <xsl:when test="name(preceding-sibling::*[1]) = 'a' and + preceding-sibling::*[1][@name]"> + <xsl:value-of select="preceding-sibling::*[1]/@name"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="generate-id()"/> + </xsl:otherwise> + </xsl:choose> + </xsl:attribute> + </fo:page-number-citation> + </fo:block> + </xsl:for-each> + </xsl:template> + + <!-- ============================================ + This complicated template creates the PDF bookmarks + supported by FOP. For each <h1> element, it + creates a bookmark for that element, then it + looks for all of the <h2> elements beneath it. + For each <h2>, it looks for all the <h3> + elements beneath it, etc. We use generate-id() + extensively so we can determine whether a given + <h1> or <h2> or <h3> is one we've seen before. + The end result of all this hard work is a set of + hierarchical bookmarks that are nested within each + other. + =============================================== --> + + <xsl:template name="generate-bookmarks"> + <fox:outline internal-destination="TableOfContents"> + <fox:label>Table of Contents</fox:label> + </fox:outline> + <xsl:for-each select="/html/body//h1"> + <xsl:variable name="current-h1" select="generate-id()"/> + <fox:outline> + <xsl:attribute name="internal-destination"> + <xsl:choose> + <xsl:when test="@id"> + <xsl:value-of select="@id"/> + </xsl:when> + <xsl:when test="name(preceding-sibling::*[1]) = 'a' and + preceding-sibling::*[1][@name]"> + <xsl:value-of select="preceding-sibling::*[1]/@name"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="generate-id()"/> + </xsl:otherwise> + </xsl:choose> + </xsl:attribute> + <fox:label> + <xsl:value-of select="."/> + </fox:label> + <xsl:for-each select="following-sibling::h2"> + <xsl:variable name="current-h2" select="generate-id()"/> + <xsl:if + test="generate-id(preceding-sibling::h1[1]) = $current-h1"> + <fox:outline> + <xsl:attribute name="internal-destination"> + <xsl:choose> + <xsl:when test="@id"> + <xsl:value-of select="@id"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$current-h2"/> + </xsl:otherwise> + </xsl:choose> + </xsl:attribute> + <fox:label> + <xsl:value-of select="."/> + </fox:label> + <xsl:for-each select="following-sibling::h3"> + <xsl:variable name="current-h3" select="generate-id()"/> + <xsl:if + test="generate-id(preceding-sibling::h2[1]) = $current-h2"> + <fox:outline> + <xsl:attribute name="internal-destination"> + <xsl:choose> + <xsl:when test="@id"> + <xsl:value-of select="@id"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$current-h2"/> + </xsl:otherwise> + </xsl:choose> + </xsl:attribute> + <fox:label> + <xsl:value-of select="."/> + </fox:label> + <xsl:for-each select="following-sibling::h4"> + <xsl:if + test="generate-id(preceding-sibling::h3[1]) = $current-h3"> + <fox:outline> + <xsl:attribute name="internal-destination"> + <xsl:choose> + <xsl:when test="@id"> + <xsl:value-of select="@id"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$current-h3"/> + </xsl:otherwise> + </xsl:choose> + </xsl:attribute> + <fox:label> + <xsl:value-of select="."/> + </fox:label> + </fox:outline> + </xsl:if> + </xsl:for-each> + </fox:outline> + </xsl:if> + </xsl:for-each> + </fox:outline> + </xsl:if> + </xsl:for-each> + </fox:outline> + </xsl:for-each> + </xsl:template> + + <!-- ============================================ + This template generates an <fo:table-column> + element for each token in the cols attribute of + the HTML <table> tag. The template processes + the first token, then invokes itself with the + rest of the string. + =============================================== --> + + <xsl:template name="build-columns"> + <xsl:param name="cols"/> + + <xsl:if test="string-length(normalize-space($cols))"> + <xsl:variable name="next-col"> + <xsl:value-of select="substring-before($cols, ' ')"/> + </xsl:variable> + <xsl:variable name="remaining-cols"> + <xsl:value-of select="substring-after($cols, ' ')"/> + </xsl:variable> + <xsl:choose> + <xsl:when test="contains($next-col, 'pt')"> + <fo:table-column column-width="{$next-col}"/> + </xsl:when> + <xsl:when test="number($next-col) > 0"> + <fo:table-column column-width="{concat($next-col, 'pt')}"/> + </xsl:when> + <xsl:otherwise> + <fo:table-column column-width="50pt"/> + </xsl:otherwise> + </xsl:choose> + + <xsl:call-template name="build-columns"> + <xsl:with-param name="cols" select="concat($remaining-cols, ' ')"/> + </xsl:call-template> + </xsl:if> + </xsl:template> + +</xsl:stylesheet>