You want to capture knowledge about a subject in a Topic Map. You want to do so in a way that facilitates generation of a web site from the Topic Map using XSLT.
The solution is based on the Cogitative Topic Maps Web Site (CTW) framework introduced to readers in XML Topic Maps, edited by Jack Park (Addison Wesley, 2002). Extreme Markup Languages initially presented this work in 2000.
Readers unfamiliar with Topic Maps may want to read Section 11.3.3 in Recipe 11.3 first or refer to Section 11.3.4 and this recipe for more resources.
The CTW uses the following mapping from topic map elements to HTML:
Topic map element |
HTML rendering |
---|---|
Topic map |
Web site |
Topic |
Web page |
Topic associations |
Site map |
Topic occurrences |
Images, graphics, text, HTML fragments, etc. |
Topic names |
Page Headers, Titles, Lists, and Hyperlink titles |
The Topic Map we create covers the subject of algorithms and, specifically, sorting algorithms. Knowledge represented in this topic map was aggregated from information resources gathered on the Internet and organized as class-subclass associations between algorithms and occurrences of types descriptions, demonstrations, and code examples in several programming languages.
Once the subject and content of the web site were decided, the ontology of the web site subjects and objects followed quite naturally. The CTW ontology layer consists of two main parts: classification of web site’s topic subjects and classification of topic characteristics that provide web-page content.
Both classifications play a very important role in controlling a web site’s look and feel. Topic types control web-page layouts, and types of topic characteristics control the styling of web-page elements and building blocks. The results are depicted in Figure 11-3.
The following subsections describe the subjects of the Sorting Algorithms web site.
The main subjects of our web site are the sorting algorithm’s various subclasses:
<topic id="sort"> ... </topic> <association> <instanceOf> <topicRef xlink:href="#_class-subclass"/> </instanceOf> <member> <roleSpec> <topicRef xlink:href="#_superclass"/> </roleSpec> <topicRef xlink:href="#sort"/> </member> <member> <roleSpec> <topicRef xlink:href="#_subclass"/> </roleSpec> <topicRef xlink:href="#simplesort"/> <topicRef xlink:href="#in-place sort"/> <topicRef xlink:href="#heapsort"/> <topicRef xlink:href="#adaptivesort"/> <topicRef xlink:href="#distributionsort"/> <topicRef xlink:href="#mergesort"/> </member> </association>
The full version of the topic map and XSLT scripts is available online at http://www.cogx.com/ctw. This section provides only some fragments to illustrate example instructions.
Each sorting algorithm can have its own subclasses—for example,
you can count four variations of in-place-sort
,
each of which may in turn have its own subclasses:
<association> <instanceOf> <topicRef xlink:href="#_class-subclass"/> </instanceOf> <member> <roleSpec> <topicRef xlink:href="#_superclass"/> </roleSpec> <topicRef xlink:href="#in-place sort"/> </member> <member> <roleSpec> <topicRef xlink:href="#_subclass"/> </roleSpec> <topicRef xlink:href="#quicksort"/> <topicRef xlink:href="#insertionsort"/> <topicRef xlink:href="#selsort"/> <topicRef xlink:href="#dimincrsort"/> </member> </association>
The National Institute of Standards and Technology (NIST) maintains an excellent web site on algorithms (http://www.nist.gov/dads/) and collects information about various computational algorithms. It maintains a web page devoted to each algorithm. This topic map uses URLs of those pages as algorithm subject identifiers of algorithms:
<topic id="insertionsort"> <subjectIdentity> <subjectIndicatorRef xlink:href="http://www.nist.gov/dads/HTML/insertsrt.html"/> </subjectIdentity>
Besides playing roles in class-subclass associations with other algorithms, sorting algorithms have other topic characteristics such as base names and occurrences.
In this topic map, sorting algorithms have names under which they are commonly recognized:
<baseName> <baseNameString>insertion sort</baseNameString> </baseName>
Sometimes they also have alternative names represented as base names
in the also-known-as
scope:
<baseName> <scope> <topicRef xlink:href="#also-known-as"/> </scope> <baseNameString>linear insertion sort</baseNameString> </baseName>
The algorithm’s description is represented as a
topic occurrence of type description
in the scope
of the description’s source. The following code is a
citation from the National Institute of Standards and Technology web
site (thus specified in the scope of the nist
topic) that can also read, “In the context of NIST,
insertion sort is described as...”
<occurrence> <instanceOf> <topicRef xlink:href="#description"/> </instanceOf> <scope> <topicRef xlink:href="#nist"/> </scope> <resourceData>Sort by repeatedly taking the next item and inserting it into the final data structure in its proper order with respect to items already inserted. </resourceData> </occurrence>
Links to algorithm demonstrations such as applets and animations are
represented as topic occurrences of type
demonstration
:
<occurrence> <instanceOf> <topicRef xlink:href="#demo"/> </instanceOf> <resourceRef xlink:href= "http://www.cosc.canterbury.ac.nz/people/mukundan/dsal/ISort.html"/> </occurrence>
You can also record links to sorting algorithms implementations and
represent them in your topic map as occurrences of type code sample
specified in the scope of a programming language in
which they are implemented. Programming languages is the other class
of topics represented on your web site that constitute an orthogonal
navigational dimension:
<occurrence> <instanceOf> <topicRef xlink:href="#code"/> </instanceOf> <scope> <topicRef xlink:href="#fortran"/> </scope> <resourceRef xlink:href="http://gams.nist.gov/serve.cgi/Module/TOMS/505/8547"/> </occurrence> <occurrence> <instanceOf> <topicRef xlink:href="#code"/> </instanceOf> <scope> <topicRef xlink:href="#java"/> </scope> <resourceRef xlink:href= "http://www.cs.ubc.ca/spider/harrison/Java/InsertionSortAlgorithm.java"/> </occurrence> </topic>
That is all the information about algorithms that we chose to represent. You will use it to build page headers, links to related algorithms, descriptions, links to pages on the Web defining that algorithm, links to algorithm demonstrations, and code samples with cross links to programming languages in which these examples are implemented.
You only need be interested in the fact that program languages are,
in their names and definitions, instances of the programming language
class:
<topic id="java"> <subjectIdentity> <subjectIndicatorRef xlink:href="http://foldoc.doc.ic.ac.uk/foldoc/foldoc.cgi?query=java"/> </subjectIdentity> <instanceOf> <topicRef xlink:href="#plang"/> </instanceOf> <baseName> <baseNameString>Java</baseNameString> </baseName> <occurrence> <instanceOf> <topicRef xlink:href="#definition"/> </instanceOf> <scope> <topicRef xlink:href="#cnet"/> </scope> <resourceData>Sun Microsystems' Java is a programming language for adding animation and other action to Web sites. The small applications (called applets) that Java creates can play back on any graphical system that's Web-ready, but your Web browser has to be Java-capable for you to see it. According to Sun's description, Java is a "simple, object-oriented, distributed, interpreted, robust, secure, architecture-neutral, portable, high-performance, multithreaded, dynamic, buzzword- compliant, general-purpose programming language." </resourceData> </occurrence> </topic>
The programming language page shown in Figure 11-4 gathers links to code samples implemented in that language and cross links to the implemented algorithms.
In the CTW framework, root
is the topic
whose subject is indicated by the topic
map document itself. In topic map terms, root topic reifies the topic
map document to which it belongs:
<topic id="default"> <subjectIdentity> <subjectIndicatorRef xlink:href="#map"/> </subjectIdentity>
When topic maps merge in CTW, this topic is added to the scopes of all topic characteristic assignments. More importantly, this topic corresponds to the home or default page of the CTW web site.
This example displays its hyperlinked name in the upper-left corner of all pages on your web site:
<baseName> <baseNameString>Sort algorithms home</baseNameString> </baseName>
This is the place to store topic map annotations and assertions about the topic map. This example is limited to the description of project and copyright metadata:
<occurrence> <instanceOf> <topicRef xlink:href="#definition"/> </instanceOf> <resourceData><![CDATA[ This web site covers the subject of algorithms and specifically sorting algorithms.<br><br> It was created for the purposes of a CTW recipe for the O'Reilly XSLT Cookbook.]]> </resourceData> </occurrence> </topic>
The root page shown in Figure 11-5 shows only the project’s description as an introduction to the web site.
First, define the root
variable
that represents the root topic: as
described earlier, this topic is indicated by the containing topic
map document:
<xsl:variable name="root" select="//topic[subjectIdentity/subjectIndicatorRef/@xlink:href = concat('#',/topicMap/@id)]"/>
The same node could be matched using the
subjectIndicator
key that matches topics using
addresses of resources that indicate them:
<xsl:key name = "subjectIndicator" match = "topic" use = "subjectIdentity/subjectIndicatorRef/@xlink:href" /> <xsl:variable name="root" select="key('subjectIndicator',concat('#',/topicMap/@id))"/>
First, generate the default page by calling the
root-page
layout template for the root
topic:
<xsl:template match="/"> <xsl:call-template name="root-page"> <xsl:with-param name="this" select="$root"/> </xsl:call-template>
Next, the code generates web pages for every subclass of the
sorting
algorithm
. Here you
call the algorithm-page
layout template with basic
sorting algorithm
as this
parameter. The template recursively calls itself to iterate over
subclasses of all subclasses:
<xsl:call-template name="algorithm-page"> <xsl:with-param name="this" select="key('topicByID','#sort')"/> </xsl:call-template>
The stylesheet generates pages for every instance of a programming
language by calling the lang-page
layout template:
<xsl:for-each select="key('instanceOf','#plang')"> <xsl:call-template name="plang-page"/> </xsl:for-each> </xsl:template>
The instanceOf
key returns all topic instances of
a class based on the class topic’s hashed IDs:
<xsl:key name = "instanceOf" match = "topic" use = "instanceOf/topicRef/@xlink:href" />
The topicByID
key returns all topic elements based
on a given topic’s hashed IDs:
<xsl:key name = "instanceOf" match = "topic" use = "instanceOf/topicRef/@xlink:href" />
As you might have noticed in the screenshots, all three layout
templates have a common subdivision into four square areas. The
common main page-building template controls this. First, instruct the
processor to create an output file relative to the output folder
specified in the $out-dir
parameter, and create
the
TITLE header
with the current topic’s base name in the
unconstrained scope. The latter is achieved by instantiating template
matching <topic>
elements in the
label
mode. Then start the page’s
subdivision into four parts. In the upper-right corner, create a
hyperlink to the home page whose label is the name of
root
topic in the unconstraint scope. The
topic-matching template in the link
mode
accomplishes this task. In the upper-right part of the page,
you’ll have a selection of links to programming
languages pages. Iterating over all instances of programming-language
topic creates this. In the lower-left quarter of the page under the
home page link, print the part of the site map corresponding to the
sorting algorithms’ classification. Finally, in the
main part of the page in the lower-right quarter, output the
main-page content pertinent to the current topic submitted to the
page
template as content
parameter:
<xsl:template name="page"> <xsl:param name="this"/> <xsl:param name="content"/> <redirect:write select="concat($out-dir,$this/@id,'.html')"> <HTML> <HEADER> <TITLE> <xsl:apply-templates select="$this" mode="label"/> </TITLE> </HEADER> <BODY> <table width="1000" height="100%" cellspacing="0" cellpadding="10"> <tr> <td width="250" height="20" bgcolor="#ffddbb" align="center"> <xsl:apply-templates select="$root" mode="link"/> </td> <td width="750" height="20" valign="top" bgcolor="#eeeeee"> <table cellspacing="10"> <tr> <xsl:for-each select="key('instanceOf','#plang')"> <td background="grey"> <xsl:apply-templates select="." mode="link"/> </td> </xsl:for-each> </tr> </table> </td> </tr> <tr> <td valign="top" bgcolor="#eeeeee"> <xsl:call-template name="sitemap"> <xsl:with-param name="classRef">#sort</xsl:with-param> <xsl:with-param name="current" select="$this/@id"/> </xsl:call-template> </td> <td valign="top" bgcolor="#ffeedd" > <xsl:copy-of select="$content"/> </td> </tr></table> </BODY> </HTML> </redirect:write> </xsl:template>
The previous template uses the baseName
-matching
template in the label
mode:
<xsl:template match="topic" mode="label"> <xsl:value-of select="baseName[not(scope)]/baseNameString"/> </xsl:template>
The baseName
matching template in the
link
mode creates a hyperlink to the
topic’s web page:
<xsl:template match="topic" mode="link"> <a href="{@id}.html"> <xsl:value-of select="baseName[not(scope)]/baseNameString"/> </a> </xsl:template>
Later in the code, you will use the
baseName
-matching template in the
subject-indicator
mode. This template creates a
hyperlink to a resource indicating the matched topic:
<xsl:template match="topic" mode="indicator"> <a href="{subjectIdentity/subjectIndicatorRef/@xlink:href}"> <xsl:value-of select="baseName[not(scope)]/baseNameString"/> </a> </xsl:template>
The sitemap
template iterates over all subclasses
of the sort
topic, creates hyperlinks to pages
corresponding to derived algorithms, and recursively calls itself to
iterate over subclasses of the subclasses:
<xsl:template name="sitemap"> <xsl:param name="classRef"/> <xsl:param name="current"/> <xsl:variable name="topic" select="key('topicByID',$classRef)"/> <xsl:choose> <xsl:when test="$topic/@id=$current"> <span class="A"> <xsl:apply-templates select="$topic" mode="label"/> </span> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="$topic" mode="link"/> </xsl:otherwise> </xsl:choose> <xsl:variable name="aref" select="key('classAssoc',$classRef)"/> <xsl:if test="$aref"> <ul> <xsl:for-each select="$aref/member [roleSpec/topicRef/@xlink:href= '#_subclass']/topicRef"> <li> <xsl:call-template name="sitemap"> <xsl:with-param name="classRef" select="@xlink:href"/> <xsl:with-param name="current" select="$current"/> </xsl:call-template> </li> </xsl:for-each> </ul> </xsl:if> </xsl:template>
The classRef
key used by the site map template
uses the ID of a given topic to match
superclass-subclass
associations for which the
topic plays super-class
role:
<xsl:key name = "classAssoc" match = "association[instanceOf/topicRef/@xlink:href= '#_class-subclass']" use = "member[roleSpec/topicRef/@xlink:href= '#_superclass']/topicRef/@xlink:href" />
Later in the code, you will use a subClassRef
key
that also matches superclass-subclass
associations, but this time using member
where the
topic plays sub-class
role:
<xsl:key name = "subClassAssoc" match = "association[instanceOf/topicRef/@xlink:href= '#_class-subclass']" use = "member[roleSpec/topicRef/@xlink:href= '#_subclass']/topicRef/@xlink:href" />
Now you are ready to consider the three layout templates.
The root-page
layout template is very simple. Call
the page template described earlier and send it the generated HTML
code for occurrences of type description
in the
content
parameter:
<xsl:template name="root-page"> <xsl:param name="this"/> <xsl:call-template name="page"> <xsl:with-param name="this" select="$this"/> <xsl:with-param name="content"> <font size="+1"> <xsl:apply-templates select="$this/occurrence [instanceOf/topicRef/@xlink:href='#description']"/> </font> </xsl:with-param> </xsl:call-template> </xsl:template>
The plang-page
layout template is a bit more
involved. It has a title composed of the name of the current topic
followed by the name of topic’s type. Then a subject
identity line points to a place elsewhere on the Web where the
topic’s subject is defined. Following it are topic
descriptions, if any. Iterate and output a link for each code
occurrence implemented in the current language. In square brackets
following the resource, place a link to the sorting algorithm
implemented in this resource:
<xsl:template name="plang-page"> <xsl:param name="this" select="."/> <xsl:call-template name="page"> <xsl:with-param name="this" select="$this"/> <xsl:with-param name="content"> <font size="+2"> <xsl:apply-templates select="$this" mode="label"/>, a <xsl:apply-templates mode="label" select="key('topicByID',$this/instanceOf/topicRef/@xlink:href)" />. </font> <br/><br/> <xsl:apply-templates select="$this/subjectIdentity"/> <xsl:apply-templates select="$this/occurrence [instanceOf/topicRef/@xlink:href='#description']"/> <xsl:variable name="codes" select="key('plang-codes',concat('#',$this/@id))"/> <xsl:if test="$codes"> <span>Sorting algorithms implemented in <xsl:apply-templates select="$this" mode="label"/>:</span> <ul> <xsl:for-each select="$codes"> <li> <a href="{resourceRef/@xlink:href}"> <xsl:value-of select="resourceRef/@xlink:href"/> </a> [<xsl:apply-templates select=".." mode="link"/>]<br/> </li> </xsl:for-each> </ul> <br/><br/> </xsl:if> </xsl:with-param> </xsl:call-template> </xsl:template>
The plang-codes
key used earlier matches all
occurrences in the topic map by any of their scope themes:
<xsl:key name="plang-codes" match="occurrence" use="scope/topicRef/@xlink:href"/>
The algorithm-page
layout template comes last. Its
title is composed of the current topic’s name
followed by also-known-as
names in square
brackets. The subject identity line is followed by the list of
superclasses, if any, from which the current sorting algorithm
inherits. Then you’ll find one or more sorting
algorithm descriptions, followed by the list of links to algorithm
demonstration occurrences and the list of code samples with cross
links to implementing programming languages in square brackets. On
the bottom of the page, you’ll list subclasses or
variations, if any, of the current sorting algorithm. Finally, the
algorithm-page
layout template calls itself
recursively to output pages for subclasses of all its subclasses:
<xsl:template name="algorithm-page"> <xsl:param name="this"/> <xsl:call-template name="page"> <xsl:with-param name="this" select="$this"/> <xsl:with-param name="content"> <font size="+2"><xsl:apply-templates select="$this" mode="label"/> <xsl:if test="$this/baseName [scope/topicRef/@xlink:href='#also-known-as']"> [<xsl:value-of select="$this/baseName [scope/topicRef/@xlink:href='#also-known-as'] /baseNameString"/>] </xsl:if> </font> <br/><br/> <xsl:apply-templates select="$this/subjectIdentity"/> <xsl:variable name="superclasses" select="key('subClassAssoc',concat('#',$this/@id)) member[roleSpec/topicRef/@xlink:href='#_superclass']/topicRef"/> <xsl:if test="$superclasses"> Inherits from <xsl:for-each select="$superclasses"> <xsl:apply-templates select="key('topicByID',@xlink:href)" mode="link"/> <xsl:if test="position( ) != last( )">, </xsl:if> </xsl:for-each> <br/><br/> </xsl:if> <xsl:apply-templates select="$this/occurrence [instanceOf/topicRef/@xlink:href='#description']"/> <xsl:variable name="demos" select="$this/occurrence [instanceOf/topicRef/@xlink:href='#demo']"/> <xsl:if test="$demos"> <span>Demonstrations: </span> <ul> <xsl:for-each select="$demos"> <li> <a href="{resourceRef/@xlink:href}">< xsl:value-of select="resourceRef/@xlink:href"/> </a><br/> </li> </xsl:for-each> </ul> <br/> </xsl:if> <xsl:variable name="codes" select="$this/occurrence[instanceOf/topicRef/@xlink:href='#code']"/> <xsl:if test="$codes"> <span>Implementations and sample code: </span> <ul> <xsl:for-each select="$codes"> <li> <a href="{resourceRef/@xlink:href}"> <xsl:value-of select="resourceRef/@xlink:href"/> </a> [<xsl:apply-templates mode="link" select="key('topicByID',scope/topicRef/@xlink:href)"/>] </li> </xsl:for-each> </ul> <br/> </xsl:if> <xsl:variable name="subclasses" select="key('classAssoc', concat('#',$this/@id))/member [roleSpec/topicRef/@xlink:href= '#_subclass']/topicRef"/> <xsl:if test="$subclasses"> See also <xsl:value-of select="$this/baseName[not(scope)]/baseNameString"/> variants: <xsl:for-each select="$subclasses"> <xsl:apply-templates select="key('topicByID',@xlink:href)" mode="link"/> <xsl:if test="position( ) != last( )">, </xsl:if> </xsl:for-each> </xsl:if> </xsl:with-param> </xsl:call-template> <xsl:variable name="aref" select="key('classAssoc',concat('#',$this/@id))"/> <xsl:for-each select="$aref/member [roleSpec/topicRef/@xlink:href='#_subclass']/topicRef"> <xsl:call-template name="algorithm-page"> <xsl:with-param name="this" select="key('topicByID',@xlink:href)"/> </xsl:call-template> </xsl:for-each> </xsl:template>
Topic Maps is a technology that accumulates and manages knowledge about real-world domains. In this case, you represented relationships between algorithms and other objects and resources. If you are careful to follow the conventions of CTW, you’ll be able to drive the creation of a web site from the topic map source.
In this solution, you were limited to just a few types of objects and relationships between them. Real-life applications are much more complicated. The main idea was to demonstrate the power and tremendous opportunities provided by the CTW framework.
In the CTW framework, a single topic map document controls both the content and structure of an entire web site. Proper CTW topic map architecture provides robust and intuitive maintenance of links between web pages, web-page content, and metadata. Web sites built according to CTW are easily merged and immune to dead links. XSLT offers a consistent look and feel, platform independence, and reusability.
You do have to pay to get all these benefits: the CTW framework requires you to think of your content in terms of topics, topic characteristics, and associations. This approach limits you to creating content only in the limits of the chosen ontology, but it helps keep the knowledge represented on the web site well organized and navigable.
XSLT enables the CTW because it provides a modular and maintainable means to transform and stylize the knowledge contained in the topic map. Dynamic CTW solutions created with XSLT scale up to several thousand topics, and static solutions are limited only by the available disk space.
XML Topic Maps: Creating and Using Topic Maps for the Web, edited by Jack Park, (Addison Wesley, 2002) is an excellent book that covers both the theory and application of topic maps in a very accessible manner.
You can find a good collection of links to resources about topic maps at http://www.dmoz.org/Computers/Artificial_Intelligence/Knowledge_Representation/Topic_Maps/.
The author maintains a site at http://www.cogx.com/ctw that further discusses topic maps and the cogitative topic maps framework. Slides from the Extreme Markup Languages presentation of CTW are available at http://www.cogx.com/Extreme2000/.