Showing:

Documentation
Source

Table of Contents

Group by:
Main stylesheet June_10_ham_annotated.xslt
Documentation

Description

 An XSLT stylesheet written on-the-fly by the 2011 DHSI "Introduction 
 to XSLT for Digital Humanists" workshop, 2011-06-10 ~11:00/11:15, and 
 then further annotated by Syd. 
Stylesheet version 2.0
[ top ]
Template /
Documentation

Description

Our first template matches the "root" or "document" node. This is the node that is the parent of the outermost element (typically TEI). It may contain comment or processing instruction nodes, can not have attribute nodes, and must have one and only one child element node. Note that while this is our first template, and it is very common practice to have a template that matches root as the 1st template, it is not required that there be a template that matches root, or that it be 1st if there is one.

Match /
Mode #default
Source
<xsl:template match="/">
  <!-- This template generates the output HTML structure, filling in the <title> -->
  <!-- using "pull" processing, and then filling in the <body> by processing the -->
  <!-- TEI <text> element. Note that this means we are ignoring all metadata other -->
  <!-- than the title, which is probably a bad idea in the real world. -->
  <html>
    <head>
      <title>
        <xsl:value-of select="/TEI/teiHeader/fileDesc/titleStmt/title[1]"/>
      </title>
    </head>
    <body>
      <xsl:apply-templates select="/TEI/text"/>
      <!-- NB: There is no template that matches the input TEI <text> element. So when -->
      <!-- templates are applied by this <apply-templates>, none is found, and the built- -->
      <!-- in rules are used. The built-in rule for any element is to process its -->
      <!-- attributes and children. In this particular case (ham.xml) there are no -->
      <!-- attributes on <text>. So basically it means to process the children. -->
    </body>
  </html>
</xsl:template>
[ top ]
Template front
Documentation

Description

Ignore the frontmatter completely. This template works by matching <front> (and thus this template gets fired instead of the built-in template), and doing nothing. Since the <template> element is empty, this is a folder of intructions that contains no instructions, as it were.

Match front
Mode #default
Source
<xsl:template match="front"/>
[ top ]
Template body
Documentation

Description

When we hit the input <body> generate an output <div> that has as its contents whatever we get by processing the contents of the input <body>. And, while we're at it, give that output <div> a @class and a some styling.

Match body
Mode #default
Source
<xsl:template match="body">
  <div class="body" style="margin-left: 5em;">
    <xsl:apply-templates/>
  </div>
</xsl:template>
[ top ]
Template div
Documentation

Description

When we hit an input TEI <div>, generate a corresponding output XHTML <div> that has as its contents whatever we get by processing the contents of the input TEI <div>.

Match div
Mode #default
Source
<xsl:template match="div">
  <!-- Note that we used a literal result element (as we usually do), -->
  <!-- which puts the output node in the output namespace. If we had -->
  <!-- used <copy>, we would generate an output element named <div>, -->
  <!-- but it would be in the TEI namespace. -->
  <div>
    <xsl:apply-templates/>
  </div>
</xsl:template>
[ top ]
Template head
Documentation

Description

We know that every TEI <head> element in the <text> portion of the input document is the child of a <div>, and that there are only 2 levels of <div> (for acts and for scenes). So here we generate an output <h2> iff this <head> is 1 <div> deep, and an output <h3> iff this <head> is 2 <div> deep.

Match head
Mode #default
Source
<xsl:template match="head">
  <!-- Since we know the name of the output XHTML element now as we -->
  <!-- write the program, but only when it is being executed, we need -->
  <!-- to dynamically generate the name of the output XHTML element. -->
  <!-- To do this we use the XSL <element> element, and give an XPath -->
  <!-- that will generate the right name at run-time as the value of -->
  <!-- the name= attribute. To indicate that we intend an XPath, -->
  <!-- not a literal name, as the value of name=, we surround it with curly -->
  <!-- braces. -->
  <!-- To determine our depth we count how many ancestor <div>s we -->
  <!-- have (1 or 2) and add 1. The return value of count() is a number, -->
  <!-- but luckily XPath is smart enough to figure out that we want the -->
  <!-- *string* "2", not the *number* "2", when used as an argument to -->
  <!-- concat(). (Which is short for "concatenate" strings.) -->
  <xsl:element name="{concat( 'h', count(ancestor::div)+1 )}">
    <!-- Process the children of the <head> that is the context node. -->
    <!-- Note that in this particular case (<head> elements in ham.xml), -->
    <!-- it turns out that there are no children of <head> other than -->
    <!-- text nodes, so using <value-of select="."> would work just as  -->
    <!-- well. -->
    <xsl:apply-templates/>
  </xsl:element>
</xsl:template>
[ top ]
Template stage
Documentation

Description

This template matches a <stage> direction, regardless of where it appears in the input hierarchy: this introduces a bug. Here we put out a <p> element, but input <stage> elements can (and do) appear inside <l> elements, for which we also put out a <p>. That means we end up with <p>-within-<p> in the output XHTML.

Match stage
Mode #default
Source
<xsl:template match="stage">
  <!-- Output a <p> with some styling ... -->
  <p style="color:red;">
    <!-- ... and put the content of the input <stage> into it, ... -->
    <!-- ... surrounded by square brackets. -->
    <xsl:text>[</xsl:text>
    <xsl:apply-templates/>
    <xsl:text>]</xsl:text>
  </p>
</xsl:template>
[ top ]
Template sp
Documentation

Description

An input TEI <sp> element gets transformed into an XHTML <div>, but while we're at at put a unique @id on the <div> so that the individual speeches can be pointed to (either by fancier stuff in this stylesheet later, or potentially by other web sites if we've generated a static page).

Match sp
Mode #default
Source
<xsl:template match="sp">
  <!-- Note the value of the id= attribute is surrounded by curly -->
  <!-- braces, meaning it is an XPath, not a literal string. (If -->
  <!-- you ever really want a curly brace, you have to use "\{" -->
  <!-- instead.) -->
  <div id="{generate-id()}">
    <!-- The generate-id() function creates a value that is guarenteed -->
    <!-- to be unique in the output document, but it might be something -->
    <!-- different each time you run the transformation. So you can -->
    <!-- easily rely on it to generate intra-document pointers (e.g., -->
    <!-- for the XHTML version of your <note> elements), but it's not -->
    <!-- so useful for generating IDs you can tell your friends to use. -->
    <xsl:apply-templates/>
  </div>
</xsl:template>
[ top ]
Template speaker
Documentation

Description

For an input TEI <speaker> element, generate an output XHTML <em> element that has some styling and has as its contents whatever we get by processing the contents of the input <speaker>, then follow that with ": ".

Match speaker
Mode #default
Source
<xsl:template match="speaker">
  <em style="display: block; float: left; margin-left: -2em; margin-right: 1ex;">
    <xsl:apply-templates/>
    <xsl:text>: </xsl:text>
  </em>
</xsl:template>
[ top ]
Template l | ab
Documentation

Description

We want to treat an input metrical line the same as input spoken prose. So this template matches either a TEI <l> or a TEI <ab> in the input, and generates an output XHTML <p> that has as its contents whatever we get by processing the contents of the input element, follwed by a line number on every 5th line. BUG: note that the count() functions in the following are counting only input <l> elements, but are applied to both <l> and <ab>.

Match l | ab
Mode #default
Source
<xsl:template match="l | ab">
  <p>
    <xsl:apply-templates/>
    <!-- The following test is a bit complicated; let's take it from the -->
    <!-- inside out. -->
    <!-- 1) take the sequence of all preceding <l> elements -->
    <!-- 2) count them -->
    <!-- 3) add one to the count -->
    <!-- 4) divide the result by 5 and keep only the remainder -->
    <!-- 5) compare that remainder to 0 -->
    <!-- Note: the parens grouping the count() and the +1 are needed, otherwise -->
    <!-- XPath thinks you want to add "1 mod 5" to the count (and "1 mod 5" is -->
    <!-- always 1). -->
    <xsl:if test="( count( preceding::l ) +1 ) mod 5 eq 0">
      <!-- OK. We have (perhaps incorrectly due to BUG, above) decided this is -->
      <!-- an every 5th line, so output the line number in square brackets. -->
      <xsl:text> [</xsl:text>
      <xsl:value-of select="count( preceding::l) +1"/>
      <xsl:text>]</xsl:text>
    </xsl:if>
  </p>
</xsl:template>
[ top ]
Output (default)
Documentation

Description

Annotation of above start-tag:

* The root element of an XSLT program is either a <stylesheet> element or a <transform> element; they're interchangeable.

* The @version attribute is the version of the XSLT language that you are going to be using; use 1.0 if you need the transformation to be in-the- browser, and 2.0 if you need fancy features. We used 2.0 in class.

* The @xpath-default-namespace attribute contains the namespace that is presumed on element tests in XPaths. In this case, the value is the TEI P5 namespace. I.e., this tells us that by default the path 'div/p' is talking about a TEI p in a TEI div (as opposed to an XHTML p in an XHTML div, e.g.). You can think of this as the namespace of the input document.

* The other two lines are namespace declarations. The first says that any element that bears the prefix "xsl:" is in the XSLT namespace (thus the XSLT <stylesheet> element itself is expressed as "xsl:stylesheet"). The second says that elements that do not have a namespace prefix are in the XHTML namespace. We use this for literal results elements (e.g., when we just write "<p>hello</p>" in a template). Thus you can think of it as the namespace of the output document.

* EXTRA INFO: The namespace declarations are *not* attributes, even though they look like attributes. What's the difference? For one thing, they are not available on the attribute:: axis (abbreviated "@"). So if you enter "/xsl:stylesheet/@xmlns" into oXygen's XPath search box, you'll find it is a valid XPath that returns no results. In fact, as you try to type it, you will probably find that when you get to typing the "@", oXygen auto-completes with @version and @xpath-default-namespace (which are attributes) but not @xmlns or @xmlns:xsl (which are not). On the other hand, if you enter "/xsl:stylesheet/namespace::node()", you should get a sequence of 3 items.


Description

Our <output> element just tells the XSLT engine that we want XHTML output and that it is permitted to insert whitespace in an attempt to make the output more readable by humans.

Output properties
method indent
xhtml yes
Source
<xsl:output method="xhtml" indent="yes"/>
[ top ]