Digital humanities


Maintained by: David J. Birnbaum (djbpitt@gmail.com) [Creative Commons BY-NC-SA 3.0 Unported License] Last modified: 2021-12-27T22:03:54+0000


SVG assignment #2

The text

This exercise uses an XML document from the Alice Project, which you can download by right-clicking on this. (Don’t just click to open it in a browser and copy, which can add some browser rendering characters that will mess up your code; right click and download.)

The root element of the Alice XML file, <alice>, contains <cast> and <titlePage> child elements, both of which you can ignore, followed by twelve child <chapter> elements. The chapters are numbered with a @which attribute, e.g., <chapter which="1">. Chapters contain paragraph elements (<p>), which contain various child elements and descendants. You are interested in the <q> elements inside the chapters (at various depths), which are used to tag quotes by characters in the story.

The task

Your goal is to begin (just begin; see below) to create a line graph that charts the number of quotes by Alice herself in each chapter. You do not have to graph any character except Alice. Your X axis marks the chapters and your Y values reflect the number of <q> elements in each chapter that have an @sp attribute equal to alice. A complete line graph might look something like http://dh.obdurodon.org/alice_svg_output_2151.svg.

Thinking about variables

Our solution uses global variables (variables that are defined once for the entire stylesheet) as well as variables that have different values for each chapter in the book (that is, for each dot in the graph). If you aren’t already comfortable with XSLT variables, you need to begin by reading up on them at http://www.w3schools.com/xsl/el_variable.asp or in the Michael Kay book.

As an example of a global variable, the amount of space between chapters on the X axis (that is, the amount of horizontal space between dots) is constant for the entire SVG graph. That is, each dot is the same distance from its neighbors as other dots are from their neighbors. If we want that distance to be, say, 100 pixels, we can define a global variable with something like:

<xsl:variable name="Xinterval" select="100"/>

We can then refer to the $Xinterval variable when we need to space out our dots while plotting them. This is a convenience variable, which means that it wasn’t absolutely necessary, since we could instead have written 100 wherever we need it. What’s convenient about the variable is that if we later decide to change the value, it could be hard to find a number inside XSLT or SVG code. If we’ve put the number in a variable definition, we can find and change it more easily. Global variables are defined as children of the root <xsl:stylesheet> element. We usually write them immediately after our <xsl:output> element, so that we can find them easily.

We can also set convenience variable values that may be different for different chapters (different dots); these are not global variables because they don’t always have the same value. For example, in the code that draws the dots for each chapter, we can set the X position of a dot with something like:

<xsl:variable name="Xpos" select="position() * $Xinterval"/>

If we’ve previously defined $Xinterval as equal to 100, this will set the value of the $Xpos variable to 100 for chapter 1 (the first of the twelve chapters, and therefore in position #1), to 200 for chapter 2, etc. We can then plot the dot with something like (you will also already have calculated the Y position and assigned that value to the variable $Ypos):

<circle cx="{$Xpos}" cy="{$Ypos} r="5" fill="red">

Note the curly braces, which create an attribute value template (AVT) that causes the variable to be interpreted and its value to be output. If you don’t use an AVT, you’ll set your X position to a literal value of $Xpos, which is invalid because the X position of an SVG <circle> element must be numeric. You don’t need curly braces for the @r attribute (the radius of the circle) because that value already is a number, and you don’t need it for the @fill (color) because that value should be a literal color name or some other representation of a color.

Putting the X position into a variable is handy because you're going to need it both to position the dot and to position the chapter label (see the labels on the X axis on our sample output at the link above). If you calculate the position for each chapter once and stash it in a variable, you reuse the variable to position two things without having to redo the calculation.

Before you start

Although we have advised you to use the push model in all of your other homework, generating SVG is a common situation where pull may be more convenient. After you create the SVG superstructure, plot the X and Y axes, and label the Y axis at intervals, you can draw the dots, the lines between dots, and the labels on the X axis either by applying templates to all <chapter> elements or by using <xsl:for-each select="//chapter">. If you use the <xsl:for-each> strategy, you’ll need only one template for the document node, and you’ll put the <xsl:for-each> inside that. If you apply templates to chapters, you’ll need two templates: a template for the document node, in which you’ll create the SVG superstructure, and a template that matches <chapter> elements.

You can can draw the dot for each chapter when you process that chapter, but to draw connecting lines between the dots, you’ll need to access information about two chapters at once. One will be the one you’re processing; the other will be either the one before or the one after. There are several ways to do that, and we’ll talk about them when we go over the solution, but whatever you do, note that with twelve chapters you have twelve dots but only eleven connecting lines. This means that one chapter (either the first or the last, depending on how you structure your code) will have to be treated differently from the others. For that reason, you may find it useful to test whether you’re at the beginning or end of the sequence of chapters with <xsl:if>.