facebook google plus twitter
Webucator's Free Introduction to XSL-FO Tutorial

Lesson: Links and Graphics

Welcome to our free Introduction to XSL-FO tutorial. This tutorial is based on Webucator's Introduction to XSL-FO course.

Lesson Goals

  • To create external and internal links.
  • To add graphics to graphics to a page.

External Links

The syntax of an external link is as follows.

<fo:basic-link external-destination="url('http://www.webucator.com')"> Webucator </fo:basic-link>

This link will not contain any formatting. To make the link blue and underlined, it should be modified as follows.

<fo:basic-link external-destination="url('http://www.webucator.com')" color="blue" text-decoration="underline"> Webucator </fo:basic-link>

The code sample below will output links for each Beatle.

Code Sample:

LinksAndGraphics/Demos/Beatles.fo
<?xml version="1.0" encoding="UTF-8"?>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
---- C O D E   O M I T T E D ----
<fo:flow flow-name="xsl-region-body">
			<fo:block space-after="10pt">
				Beatles
			</fo:block>
			<fo:list-block start-indent="20pt">
				<fo:list-item>
					<fo:list-item-label end-indent="label-end()">
						<fo:block font-weight="bold">
							<fo:character character="&#x2022;" />
						</fo:block>
					</fo:list-item-label>
					<fo:list-item-body start-indent="body-start()">
						<fo:block>
							<fo:basic-link 
								external-destination="url('http://www.paulmccartney.com')" 
								color="blue" text-decoration="underline">
									Paul McCartney
							</fo:basic-link>
						</fo:block>
					</fo:list-item-body>
				</fo:list-item>
				<fo:list-item>
					<fo:list-item-label end-indent="label-end()">
						<fo:block font-weight="bold">
							<fo:character character="&#x2022;" />
						</fo:block>
					</fo:list-item-label>
					<fo:list-item-body start-indent="body-start()">
						<fo:block>
							<fo:basic-link 
								external-destination="url('http://www.johnlennon.com')" 
								color="blue" text-decoration="underline">
									John Lennon
							</fo:basic-link>
						</fo:block>
					</fo:list-item-body>
				</fo:list-item>
				<fo:list-item>
					<fo:list-item-label end-indent="label-end()">
						<fo:block font-weight="bold">
							<fo:character character="&#x2022;" />
						</fo:block>
					</fo:list-item-label>
					<fo:list-item-body start-indent="body-start()">
						<fo:block>
							<fo:basic-link 
								external-destination="url('http://www.georgeharrison.com')" 
								color="blue" text-decoration="underline">
									George Harrison
							</fo:basic-link>
						</fo:block>
					</fo:list-item-body>
				</fo:list-item>
				<fo:list-item>
					<fo:list-item-label end-indent="label-end()">
						<fo:block font-weight="bold">
							<fo:character character="&#x2022;" />
						</fo:block>
					</fo:list-item-label>
					<fo:list-item-body start-indent="body-start()">
						<fo:block>
							<fo:basic-link
								external-destination="url('http://www.ringostarr.com')" 
								color="blue" text-decoration="underline">
									Ringo Starr
							</fo:basic-link>
						</fo:block>
					</fo:list-item-body>
				</fo:list-item>
				<fo:list-item>
					<fo:list-item-label end-indent="label-end()">
						<fo:block font-weight="bold">
							<fo:character character="&#x2022;" />
						</fo:block>
					</fo:list-item-label>
					<fo:list-item-body start-indent="body-start()">
						<fo:block>
							<fo:basic-link 
								external-destination="url('http://www.webucator.com')" 
								color="blue" text-decoration="underline">
									Nat Dunn
							</fo:basic-link>
						</fo:block>
					</fo:list-item-body>
				</fo:list-item>
			</fo:list-block>
		</fo:flow>
	</fo:page-sequence>
</fo:root>

The result would look like this.

Graphics

The syntax of adding a graphic is as follows.

<fo:external-graphic src="url('http://www.webucator.com/images/logo.gif')" width="300px" height="75px"/>

The following code shows how we could insert a picture of the Beatles above the list of links from the last example.

Code Sample:

LinksAndGraphics/Demos/Beatles2.fo
<?xml version="1.0" encoding="UTF-8"?>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
---- C O D E   O M I T T E D ----
<fo:flow flow-name="xsl-region-body">
			<fo:block space-after="10pt">
				<fo:external-graphic src="url('Images/beatles.jpg')" 
					width="340px" height="238px"/>
			</fo:block>
---- C O D E   O M I T T E D ----
</fo:flow>
	</fo:page-sequence>
</fo:root>

The result would look like this.

Adding Links and Graphics

Duration: 15 to 20 minutes.

In this exercise, you will use XSLT to generate the XSL-FO links shown in the example above.

  1. Open LinksAndGraphics/Exercises/Beatles.xsl for editing.
  2. Modify this document so that each Beatle from the associated Beatles.xml file is output as a link.
  3. Replace the word "Beatles" in the first block inside the xsl-region-body flow with the beatles.jpg image from the Images folder.
  4. To test your solution, transform LinksAndGraphics/Exercises/Beatles.xml against LinksAndGraphics/Exercises/Beatles.xsl.

Code Sample:

LinksAndGraphics/Exercises/Beatles.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
			xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
			xmlns:fo="http://www.w3.org/1999/XSL/Format">
	<xsl:output method="xml" indent="yes"/>
	<xsl:template match="/beatles">
		<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
---- C O D E   O M I T T E D ----
<fo:page-sequence master-reference="list">
				<fo:static-content flow-name="xsl-region-before" text-align="center">
					<fo:block font-size="20pt" font-weight="bold">
						The Beatles
					</fo:block>
				</fo:static-content>
				<fo:flow flow-name="xsl-region-body">
					<fo:block space-after="24pt" font-weight="bold">
						The Beatles
					</fo:block>
					<fo:list-block start-indent="20pt">
						<xsl:apply-templates/>
					</fo:list-block>
				</fo:flow>
			</fo:page-sequence>
		</fo:root>
	</xsl:template>
	<xsl:template match="beatle">
		<fo:list-item>
			<fo:list-item-label end-indent="label-end()">
				<fo:block font-weight="bold">
					<fo:character character="&#x2022;"/>
				</fo:block>
			</fo:list-item-label>
			<fo:list-item-body start-indent="body-start()">
				<fo:block>
					<xsl:value-of select="name/firstname"/>
						<xsl:text> </xsl:text>
					<xsl:value-of select="name/lastname"/>
				</fo:block>
			</fo:list-item-body>
		</fo:list-item>
	</xsl:template>
</xsl:stylesheet>

Solution:

LinksAndGraphics/Solutions/Beatles.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
			xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
			xmlns:fo="http://www.w3.org/1999/XSL/Format">
	<xsl:output method="xml" indent="yes"/>
	<xsl:template match="/beatles">
		<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
---- C O D E   O M I T T E D ----
<fo:page-sequence master-reference="list">
---- C O D E   O M I T T E D ----
<fo:flow flow-name="xsl-region-body">
					<fo:block space-after="24pt" font-weight="bold">
						<fo:external-graphic src="url('Images/beatles.jpg')" 
							width="340px" height="238px"/>
					</fo:block>
					<fo:list-block start-indent="20pt">
						<xsl:apply-templates/>
					</fo:list-block>
				</fo:flow>
			</fo:page-sequence>
		</fo:root>
	</xsl:template>
	<xsl:template match="beatle">
		<fo:list-item>
			<fo:list-item-label end-indent="label-end()">
				<fo:block font-weight="bold">
					<fo:character character="&#x2022;"/>
				</fo:block>
			</fo:list-item-label>
			<fo:list-item-body start-indent="body-start()">
				<fo:block>
					<fo:basic-link external-destination="url('{@link}')" 
						color="blue" text-decoration="underline">
						<xsl:value-of select="name/firstname"/>
							<xsl:text> </xsl:text>
						<xsl:value-of select="name/lastname"/>
					</fo:basic-link>
				</fo:block>
			</fo:list-item-body>
		</fo:list-item>
	</xsl:template>
</xsl:stylesheet>

Internal Links

Internal links are links from one location in a document to another location in the same document. There are two steps to creating internal links:

  1. Give a unique ID to the location being linked to. IDs are specified with the id attribute. The value can be hard coded or generated. In the example below, we use the generate-id() XSLT function to generate IDs:
    <fo:block font-weight="bold" font-size="larger" 
    	id="{generate-id(.)}" break-before="page">
    		<xsl:value-of select="."/>
    	</fo:block>
  2. Create the link to that location. As with external links, internal links are created with the <fo:basic-link> tag. The internal-destination attribute should be set to the value of an ID elsewhere in the document.
    <fo:basic-link internal-destination="{generate-id(.)}">
    	<xsl:value-of select="."/>
    </fo:basic-link>

The complete example is below:

Code Sample:

LinksAndGraphics/Demos/Stories.html
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="Stories.xsl"?>
<html>
	<head>
		<title>Stories</title>
		<link href="Styles.css" rel="stylesheet" type="text/css" />
	</head>
	<body>
		<a name="top"></a>
		<h1>Stories</h1>
		<hr />
		<div id="divPooh">
			<a name="pooh" />
			<h2>POOH GOES VISITING - A.A. Milne</h2>
			<p>Pooh always liked a little something at eleven o'clock in the morning,
---- C O D E   O M I T T E D ----
</div>
		<div id="divTea">
			<a name="alice"></a>
			<h2>A MAD TEA-PARTY - Lewis Carroll</h2>
			<p>There was a table set out under a tree in front of the house, and the 
---- C O D E   O M I T T E D ----
</div>
		<div id="divCupid">
			<a name="naughtyboy"></a>
			<h2>THE NAUGHTY BOY - Hans Christian Andersen</h2>
			<p>Along time ago, there lived an old poet, a thoroughly kind old poet.
---- C O D E   O M I T T E D ----
</div>
	</body>
</html>

Code Sample:

LinksAndGraphics/Demos/Stories.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
			xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
			xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
	<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
		<fo:layout-master-set>
---- C O D E   O M I T T E D ----
</fo:layout-master-set>
		<fo:page-sequence master-reference="TOC">
			<fo:static-content flow-name="xsl-region-before">
				<fo:block border-bottom-width="thin" 
					border-bottom-style="solid" border-bottom-color="green"
					font-weight="bold">
					Table of Contents
				</fo:block>
			</fo:static-content>
			<fo:flow flow-name="xsl-region-body">
				<xsl:apply-templates mode="TOC"/>
			</fo:flow>
		</fo:page-sequence>
		<fo:page-sequence master-reference="Stories">
			<fo:static-content flow-name="xsl-region-before">
				<fo:block border-bottom-width="thin" 
					border-bottom-style="solid" border-bottom-color="green"
					font-weight="bold">
					Story
				</fo:block>
			</fo:static-content>
			<fo:flow flow-name="xsl-region-body">
				<xsl:apply-templates mode="Stories"/>
			</fo:flow>
		</fo:page-sequence>
	</fo:root>
</xsl:template>
<xsl:template match="body/div/h2" mode="TOC">
	<fo:block font-weight="bold" font-size="larger">
		<fo:basic-link internal-destination="{generate-id(.)}">
			<xsl:value-of select="."/>
		</fo:basic-link>
	</fo:block>
</xsl:template>
<xsl:template match="body/div/h2" mode="Stories">
	<fo:block font-weight="bold" font-size="larger" 
		id="{generate-id(.)}" break-before="page">
		<xsl:value-of select="."/>
	</fo:block>
</xsl:template>
<xsl:template match="body/div/p" mode="Stories">
	<fo:block margin-top="12pt">
		<xsl:apply-templates mode="Stories"/>
	</fo:block>
</xsl:template>
<xsl:template match="head | h1 | a | p" mode="TOC"/>
<xsl:template match="head | h1 | a" mode="Stories"/>
</xsl:stylesheet>

The document being transformed is Stories.html, an HTML document containing several children's stories. The XSLT, Stories.xsl, transforms the HTML document into a FO document with two page sequences: one for a rudimentary table of contents containing the story titles and the other for the stories themselves. The output is shown below with the links and headings called out.

Creating Internal Links

Duration: 15 to 20 minutes.

In this exercise, you will practice creating internal links by creating a PDF that looks like LinksAndGraphics/Solutions/Lyrics.pdf.

  1. Open and examine LinksAndGraphics/Exercises/Lyrics.xml. This document contains 50 classic rock songs. The DTD for Lyrics.xml is shown at the end of these instructions. The basic structure is as follows:
    • Root Element: Songs
      • Attributes: Source, Image
      • Elements: Song (repeatable)
        • Attributes: Artist
        • Elements: Title (contains text), Lyrics (contains text)
  2. Open LinksAndGraphics/Exercises/Lyrics.xsl for editing.
  3. Most of the document, including all the page masters, is created for you. You will do the following:
    • In the body of the page sequence that references the "TitlePage" master, add the ClassicRock.gif image from the Images folder.
    • In the body of the page sequences that reference the master pages called "Song1", "Song2", etc, list the song titles, artists and lyrics so that each song is displayed as shown below:The trick to getting the lyrics to break at line breaks is to set the linefeed-treatment attribute of the containing block to "preserve".
    • In the body of the page sequence that references the "TOC" master, list all the song titles from Lyrics.xml and make them links to the song lyrics, which you added in the previous step.
  4. To test your solution, transform LinksAndGraphics/Exercises/Lyrics.xml against LinksAndGraphics/Exercises/Lyrics.xsl.

Code Sample:

LinksAndGraphics/Exercises/Lyrics.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 	xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
	<xsl:output method="xml" indent="yes"/>
	
	<xsl:template match="/">
		<fo:root>
---- C O D E   O M I T T E D ----
<!--BEGIN PAGE SEQUENCES-->
			<fo:page-sequence master-reference="TitlePage" 
				force-page-count="end-on-even">
				<fo:flow flow-name="xsl-region-body">
					<fo:block text-align="center" font-size="18pt" id="TitlePage">
						<fo:block font-weight="bold" margin-bottom="1cm">
								Top <xsl:value-of select="count(//Song)"/> 
								Classic Rock Songs of All Time
						</fo:block>
						<!--Add the ClassicRock.gif image from the Images folder-->
					</fo:block>
				</fo:flow>
			</fo:page-sequence>
			
			<fo:page-sequence master-reference="TOC">
---- C O D E   O M I T T E D ----
<fo:flow flow-name="xsl-region-body">
					<fo:block font-family="Helvetica" font-size="22pt" 
						font-weight="bold" text-align="center" space-after=".2in" id="TOC">
						Table of Contents
					</fo:block>
					<!--
						List all the song titles from Lyrics.xml.  
						Make them Links to the song lyrics.
					-->
					<fo:block id="LastPageToc" break-after="odd-page"/>
				</fo:flow>
				
			</fo:page-sequence>
			
			<fo:page-sequence master-reference="Song" initial-page-number="1">
---- C O D E   O M I T T E D ----
<fo:flow flow-name="xsl-region-body">
					<!--
						List the song titles, artists and lyrics in the following format:

						Song TItle
							- Artist

						Lyrics
					-->
					<fo:block id="LastPage"/>
				</fo:flow>
			</fo:page-sequence>
			<!--END PAGE SEQUENCES-->
			
		</fo:root>
	</xsl:template>
	
</xsl:stylesheet>

Solution:

LinksAndGraphics/Solutions/Lyrics.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
			xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
			xmlns:fo="http://www.w3.org/1999/XSL/Format">
	<xsl:output method="xml" indent="yes"/>
	
	<xsl:template match="/">
		<fo:root>
---- C O D E   O M I T T E D ----
<!--BEGIN PAGE SEQUENCES-->
			<fo:page-sequence master-reference="TitlePage" 
				force-page-count="end-on-even">
				<fo:flow flow-name="xsl-region-body">
					<fo:block text-align="center" font-size="18pt" id="TitlePage">
						<fo:block font-weight="bold" margin-bottom="1cm">
								Top <xsl:value-of select="count(//Song)"/>
								Classic Rock Songs of All Time
						</fo:block>
						<fo:block text-align="center">
							<fo:external-graphic src="url('{/Songs/@Image}')"/>
						</fo:block>
					</fo:block>
				</fo:flow>
			</fo:page-sequence>
---- C O D E   O M I T T E D ----
<fo:flow flow-name="xsl-region-body">
					<fo:block font-family="Helvetica" font-size="22pt" 
						font-weight="bold" text-align="center" space-after=".2in" id="TOC">
						Table of Contents
					</fo:block>
					<xsl:for-each select="Songs/Song">
						<fo:block font-family="Helvetica" font-size="12pt" font-weight="bold" 
							space-after=".1in">
							<fo:basic-link internal-destination="{generate-id(Title)}">
								<xsl:value-of select="Title"/>
							</fo:basic-link>
						</fo:block>
					</xsl:for-each>
					<fo:block id="LastPageToc" break-after="odd-page"/>
				</fo:flow>
				
			</fo:page-sequence>
			
			
			<fo:page-sequence master-reference="Song" initial-page-number="1">
---- C O D E   O M I T T E D ----
<fo:flow flow-name="xsl-region-body">
				
					<xsl:for-each select="Songs/Song">
						<fo:block font-weight="bold" font-size="14pt" font-family="Times" 
							id="{generate-id(Title)}" break-before="page">
							<xsl:number format="1. "/>
							<xsl:value-of select="Title"/>
						</fo:block>
						<fo:block font-size="12pt" font-style="italic" font-family="Times" 
							margin-bottom=".1in" margin-left=".2in">
								- <xsl:value-of select="@Artist"/>
						</fo:block>
						<fo:block linefeed-treatment="preserve" white-space-collapse="false" wrap-option="wrap" white-space-treatment="preserve" font-size="10pt">
							<xsl:value-of select="Lyrics"/>
						</fo:block>
					</xsl:for-each>
					
					<fo:block id="LastPage"/>
					
				</fo:flow>
			</fo:page-sequence>
				
			<!--END PAGE SEQUENCES-->	
			
		</fo:root>
	</xsl:template>
	
</xsl:stylesheet>