Chapter 25. LEMDO Development

This chapter of our documentation is still in beta. We welcome feedback, corrections, and questions while we finalize the page in our 2024–2025 work cycle.

Building the LEMDO Schemas

What and where are the LEMDO schemas?

When someone is editing a LEMDO text, they’re making use of two different schemas, which Oxygen is aware of in the background; these include a RELAX NG schema (lemdo.rng) and a Schematron schema (lemdo.sch). If you’re a programmer creating e.g. XSLT code for the project, there is another schema which helps to standardize the codebase: technical.sch. Finally, when the various TEI versions of each XML file are created at build time, they are also validated against a second pair of schemas, tei_all_LEMDO.rng and tei_all_LEMDO.sch.
All of these schemas are found in the data/sch folder, alongside the files from which they are generated: lemdo.odd, technical.odd, and tei_all_LEMDO.odd. You will also see three matching XSLT files, lemdo.xsl, technical.xsl, and tei_all_LEMDO.xsl. These are the pre-processed versions of the Schematron (*.sch) files used to do Schematron validation. The Schematron language is transformed into XSLT before being applied to a document for validation purposes, and these XSLT files are pre-generated so that this process only has to be done once.
Schemas and their associated sources are only usually edited by senior editors, project managers, or programmers. Anyone else who would like to see a change to the schema should make a suggestion to the project leaders, or raise an issue on GitHub.

How to build the schemas

Whenever a change is made to a LEMDO schema, it is usually done in the appropriate ODD file (although not always: see below). If, for example, a new Schematron rule is added (in the form of a TEI <constraintSpec> to the lemdo.odd file, the schemas will have to be rebuilt before that rule can take effect. The schema build process is handled by an Ant file, code/schema/buildBaseOdd.xml. This file builds all three ODD files to generate all their outputs, and handles all complexity automatically. We recommend that you run this every time you make any changes to any of the ODD files or related files, even if it seems that some rebuilds may not be required. It doesn’t take long to run.
To build the schemas from the ODD files, you need to be on a Linux or Mac computer; Windows will not work. You can run the build process in two different ways:
With the lemdo_all.xpr project open in Oxygen, open the data/sch/lemdo.odd file, and press the red triangle. This will run the entire process.
At the command line, go to code/schema, and run:
ant -f buildBaseOdd.xml
The results should be exactly the same: all the associated files will be refreshed, and changes can be committed if they are as expected. Before committing changes, though, we recommend that you validate all the existing files as follows: Navigate to the lemdo root folder, and run:
svn update && ant quickValidateSource
This will take some time to run, but it will validate all the existing XML files in the project with the rebuilt schemas. If the change you made has caused any of these files to become invalid, you will need to figure out what the problem is.

Complexities to be aware of

The lemdo.odd file in particular is large and complicated, and if you look through it, you will see some sections that have comments like this:
<!-- DO NOT EDIT: These values are generated from the taxonomies document. --><!-- Any changes made will have no effect. -->
These comments appear in locations where the ODD content is not constructed by hand, but is generated as part of the schema build process, taking XML structures from the TAXO1.xml document (typically taxonomies/categories) and generating from them (for example) <valList> elements in the ODD file, which are then processed into attribute values in the RELAX NG schema. We do things this way because it’s easier for senior editors to maintain taxonomies in the form of TEI <taxonomy> elements than to hand-edit the ODD file elements, but also because we use the <taxonomy> elements in other ways, such as rendering them into documentation tables. A <taxonomy> ’s descendant <category> elements can be usefully organized into a nested hierarchy, whereas a <valList> has to be flat.
This means that when you need to make a change to some component in the RELAX NG file, you should first check to see if it is encoded directly in the ODD file, or whether the content in the ODD file has a comment telling you that it is generated from somewhere else; if the latter is true, you will need to make the change in the other location before regenerating the schemas.

TEI sources and requirements for building schemas

In the lemdo root directory you will see a directory called Stylesheets-local. This contains a local copy of the parts of the TEI Stylesheets collection which are required to build ODD files into schemas, along with a file called p5subset.xml, which is a complete copy of all the TEI element and attribute definitions from the TEI standard. We use static copies of these files rather than reaching out to the TEI website to get the latest fresh copies of them for two reasons:
The TEI site is sometimes unavailable, so we don’t want to be dependent on it to build our schemas.
The TEI source code and Stylesheets are updated at least twice a year, and each new release may introduce changes which result in some of our documents being invalid in some way.
Generally, we like to stay up to date with the latest versions of the TEI and Stylesheets, but because updates may result in problems, we need to stage them carefully. When a new version of TEI is released, we recommend that a programmer on the project approach the update as follows:
Make sure you have plenty of time available to devote to any emergent issues.
Run svn update in the LEMDO root folder.
Make sure the TEI website is available and working.
Run this command to update the local copies of the Stylesheets:
ant globals.getTeiSchemaBuildRequirements
This command should retrieve new copies of the Stylesheets and p5subset.xml, and copy the relevant files from the download location (a folder called Stylesheets) into the Stylesheets-local folder, overwriting the existing ones.
Move to the code/schema folder, and run:
ant -f buildBaseOdd.xml
If that succeeds in building all the schemas, then go back to the LEMDO root folder and run:
ant quickValidateSource
Wait until all the validation has completed (it takes a while).
If everything succeeded—in other words, if the schemas all built successfully, and all the LEMDO documents were valid—then you can commit all the changes. However, if anything did not work, you will need to figure out and solve the problem, or roll back all the changes:
svn revert --recursive .

Release an anthology

Introduction to Anthology Releases explains the release process from the point of view of the editor. This document describes the technical process of taking a built anthology edition and posting it on the LEMDO website.

Introduction

The LEMDO project guarantees that all previous editions of an anthology will remain available permanently, so that any existing citation pointing to an older anthology can still be verified. For this reason, we do not overwrite previous editions with new editions. Instead, they exist side by side. Each anthology has a unique lower case identifier (douai, classroom, moms, peer-review etc.) which is used in build commands, and is also the name of the directory in data/anthologies which contains the anthology.
Editions are published at the URL: https://lemdo.uvic.ca/[anthology]_editions/[edition_number]. So, for example, you will see:
https://lemdo.uvic.ca/classroom_editions/
https://lemdo.uvic.ca/classroom_editions/0.1/
https://lemdo.uvic.ca/classroom_editions/0.2/
Alongside the _editions folder is a symlink (symbolic link) which is named for the edition (here “classroom”), and which points to the latest edition:
classroom -> classroom_editions/0.2
So anyone who browses https://lemdo.uvic.ca/classroom will be looking at the latest edition; but anyone who wants to see a specific edition can browse the url for that edition.

Steps in implementing a release

First, check the edition diagnostics to make sure that all items are showing as OK (green). The edition diagnostics are found on the Jenkins server at products/[anthology]/anthologyStatus.html. If there are still incomplete items, you cannot release; the editorial team will have to solve all the remaining problems.
If all the diagnostics items are green, do a thorough check of the anthology build on Jenkins to make sure the editors have not missed anything.
Decide on the edition number for this edition. Generally this will take the form “x.y” where x and y are integers. The edition number is stored in the repository file data/anthologies/[anthology]/VERSION. In between editions, this may be set to an intermediate number such as “x.y.z,” or it might have a suffix “a” (for alpha) or “b” (for beta). You need to change the VERSION file so that it shows the correct edition number for the new release, without any alpha or beta or third digit (unless the editors want the third digit). Then commit your change to this file.
Next, you need to create a fresh build for the anthology, which will incorporate the change to the VERSION file and the correct svn revision for that change. There are a couple of ways to do this. You could either:
wait for Jenkins to build all of lemdo-dev and then the anthology; or
build lemdo-dev and the anthology yourself on your local computer.
The latter will be quicker. This command, run in the root of the lemdo repository, will accomplish it (using the example of the peer-review anthology. The first ant command runs the main build of lemdo-dev, and the second command then constructs the anthology based on the products in the lemdo-dev build.
ant && ant forceBuildAnthology -Danthology.id=peer-review
When this process completes, you will find the following folder: products/peer-review/site.
However, if you would rather let Jenkins do the build, you can wait for the LEMDO-anthologies job on Jenkins to complete, and then you can go into the Last Successful Artifacts, then into the folder for the relevant anthology, click on site, then scroll to the bottom and click on “(all files in zip)” to download a zip file containing the site folder.
Log into the NFS filesystem as the hcmc user, and navigate to the hcmc/www/lemdo folder.
cd into the [anthology]_editions folder (so for the peer-review anthology, the peer-review_editions folder).
Create a new subfolder for the new edition (e.g. 0.3).
Use scp or an sftp tool to upload the contents of the site folder on your local computer into the subfolder you just created.
IMPORTANT: go to the URL for your new edition and test it thoroughly. The URL will be https://lemdo.uvic.ca/[anthology]/[edition_number]/, so for example https://lemdo.uvic.ca/peer-review_editions/0.3/ Make sure everything you see is correct: the right edition number, date/time and svn revision in the footer, all pages functioning, and so on.
Finally, when you are happy that the edition has been successfully uploaded, you can change the symlink to point to your new edition. SSH into the home1t filesystem as hcmc, navigate to hcmc/www/lemdo, and run the following commands to first delete the existing symlink, and then add a new symlink. It is advisable to do this in a single command (using the peer-review anthology as an example):
rm peer-review && ln -s peer-review_editions/0.3 peer-review
This will create a new symlink which points to the 0.3 edition.
Test whether the site is working properly at the canonical URL (in other words, the URL lemdo.uvic.ca/[anthology] is showing the new edition).
Now back up your local copy of this edition of the anthology to Squash. It’s good to have a copy stashed away.
Finally, edit the VERSION file to set it to the next interim version, and commit to svn.

Page and Document Titles

Here we lay out basic assumptions and encoding guidelines that lie behind what ends up right at the top of every page: the page title.

Basics

The anthology template files all include an XHTML <h2> element which appears as the first item in the <article> element. That <h2> is the trigger leading to the insertion of the page title(s).
We never take the page title from the content of the TEI <text> element. Our basic assumption is that the title appearing at the top of a page on the site is drawn from the content of the <titleStmt> in the <teiHeader> , according to these rules:
If there is a single <title> element with @type=main, then the contents of that element are processed into an XHTML <h2> element.
If there is no <title> with @type=main, but there is a single <title> element with no @type attribute, then the contents of that element are processed into an XHTML <h2> element.
If there is a <title> element with @type=sub, then that element is processed into an XHTML <h3> element.
All other <title> elements in the header <titleStmt> are ignored for the purposes of rendering the main heading on the page.

TEI <front> Elements

<front> elements should only be used in primary source documents, and should only contain genuine transcribed front matter from a primary source document. Any front element in a primary source document will be processed and rendered following the main page title created following the rules above.

Bylines and Other Front-Like Things in Born-Digital Documents

If you need to provide bylines, prefatory statements, or other such content at the head of the page in a born-digital or mixed-content document, put this information at the beginning of the <body> .

How the Table of Contents is Generated for Semi-Diplomatic Transcriptions

Semi-diplomatic transcriptions vary widely in their original form and in the encoding practices of their editors, but when a play is rendered for the end-user, a table of contents needs to be constructed to appear in the slide-out Content tab on the website. For a non-diplomatic text, the TOC will be constructed using the text node of the <head> element of any <div> elements in the text which have a <head> , since these are obviously the major divisions in the text (usually act-scene numbers or scene numbers), but for semi-diplomatic transcriptions, there may well be no such obvious structure to draw on.
Therefore a rather complicated algorithm tries to decide what components of the text should best be used to create a useful TOC. This is how the process works:
By default, <pb> elements having a signature or folio number in their @n attribute will be used.
However, if the text contains 20 or more <label> elements, then these are assumed to be more suitable text-division headings, and will be used instead. (For an example, see the texts in the Douai Shakespeare Manuscript Project.)
If 20 or more <label> elements have @n attributes, then only the <label> elements having @n attributes will be used, and the text of the TOC entries will be taken from the @n attributes.
If more than 20 <label> elements exist, but fewer than 20 have @n attributes, then all <label> elements will be used, but whenever a <label> has @n, its value will be used for the TOC entry text instead of the content of the label.
Why so complicated? While a TOC constructed from <pb> elements may be very straightforward, it is not very helpful to a general reader looking for the major sections of the text, and it may end up being extremely long, so <label> is usually a better choice if the text contains headings or similar markers which can be tagged as labels. However, the text content of a <label> element may not be very helpful in itself; it might look like this:
<label>Act<choice>
  <abbr>
    <g ref="g:us_Eng"></g>
  </abbr>
  <expan>us</expan>
</choice> jmus</label>
which may be puzzling to a reader. In such a case, the encoder can add the @n attribute to provide a more helpful label for the TOC:
<label n="Actus Primus">Act<choice>
  <abbr>
    <g ref="g:us_Eng"></g>
  </abbr>
  <expan>us</expan>
</choice> jmus</label>
and this will be used in preference to the textual content. The @n attribute can be used on all <label> s to create an entirely curated TOC if that is preferred.
LEMDO’s long-term plan for most texts other than Douai texts is to mobilize the <milestone> element in order to note correspondences between places in the semi-diplomatic transcription and the modernized text. Many semi-diplomatic transcriptions already contain commented-out <milestone> elements. When a modernized text is finalized, we will be able to finalize the milestone elements in the semi-diplomatic transcription by adding a @corresp attribute with a value of the @xml:id value of a scene or act <div> in the modernized text. We will also add an @n attribute whose value will be used to generate a TOC of act-scene or scene beginnings. Ideally, users will be able to toggle between a signature TOC (A1r, A1v, A2r, A2V, etc) and a milestone TOC.

Processing Pointers, Links, and References

Processing of References

LEMDO has thousands of <ref> elements that point to editions, anthologies, components therein, and to resources outside LEMDO. These are all processed into HTML hyperlinks for the static site.
Our processing does not do anything with <ref> elements in PDFs. Any pointing you do inside a file with the <ref> element will result in nothing in a PDF.
The <ref> and <ptr> elements can co-exist because they are pointing to xml:ids, but only the <ptr> element can be converted to strings at build time in LaTeX.

Example: Processing of a Reference in a PDF

Encoding:
<note type="gloss">Monarchs (<ref type="bibl" target="bibl:OEDT2">
  <title level="m">OED</title>
</ref>
  <term>prince</term>, n. 1.).</note>
Rendering in the PDF:
princes Monarchs (OED prince, n. 1.). The Chorus … emdH5_FM_annotations line 95

Processing of Pointers

We would like to have a canonically-structured textual reference in the output. In the digital edition, we want the A.S.Sp. system (e.g., 5.1.2) plus a precise hyperlink. In the print edition, we want the A.S.L reference system (e.g., 2.3.101). We do not want to have the author of the critical text write a literal 2.3.101 into their document, because lineation may change as the text is edited, but we do want a critical introduction to be able to contain A.S.L citations when it is printed. The actual text in the parenthetical citation must be generated at build time.
LEMDO therefore has two different processing chains for pointers: one for the digital edition and one for the print edition (a camera-ready PDF that can be downloaded or printed through print-on-demand services).
For online publication, we generate a parenthetical citation that gives LEMDO’s canonical reference system (A.S.Sp.). Clicking on the citation takes one directly to the part of the speech being cited.
For the PDF, we generate a parenthetical citation that gives A.S.L (act, scene, line number) using the line numbers generated for the PDF at the time we make the PDF.
For example, an editor might use a <ptr> element in their critical introduction to point to anchors in the middle of a long speech in their modernized text. In the processing for the PDF, LEMDO will calculate and supply the A.S.L, so that reader may find the exact line(s) being cited in the generated parenthetical citation. For the online version, the parenthetical citation will be A.S.Sp. but the hyperlink on the citation will go directly to the target point in the speech.

Citing Published Texts

One approach to the mutability of online texts produced both within and outside LEMDO is to choose a specific print edition of source texts (such as the New Oxford Shakespeare) to which all references can point. This has the obvious disadvantage that such a pointer cannot be made into any kind of link, but links are fragile anyway, and this approach also fits with the numerous citations of critical print texts which occur throughout critical material.

Pointing within Edition Directories

We have seen above that certain types of citation between texts are not very robust, because texts are (for the forseeable future, anyway) steadily evolving, and even our principles for lineation and our citation styles are not absolutely finalized. However, when you’re editing critical material that will be bundled with an edition of a text in (for example) a print volume, you need to be able to point into the text, just as you need to be able to attach annotations to specific points in the text. There are two scenarios in which we do this:

Pinning Annotations

Annotations are <note> elements (documented in detail in Encode Annotations) which live in separate files outside the plays to which they refer. At build time, annotations may be rendered as links with popups, or as footnotes in a print edition.
Annotations are pinned to a location in the text using a system of anchors and pointers which is documented in Encode Annotations.

Local Pointers

Although we know that pointing between electronic texts which are in constant development is inherently fragile, there are situations in which we need to be able to create a canonically-formatted text reference in a critical text to a specific point in the text which is being discussed. If these texts are in the same edition directory, then we know they will be built at the same time, and therefore any output created will be consistent across that build.
This enables us to solve the particular problem noted above, where we would like to have a canonically-structured textual reference such as 2.3.45 appearing in the critical text, and this is particularly important for the print texts that we are going to publish. We don’t want to have the author of the critical text write a literal 2.3.45 into their document, because lineation may change as the text is edited, but we do want a critical introduction to be able to contain such text when it is printed; therefore the actual text must be generated at build time. We do this using a <ptr> element with @type=localCit:
<div><!-- In the critical text: -->
  <p><!-- ... --> the king addresses the <quote>noble English</quote> (<ptr type="localCit" target="doc:emdH5_FM.xml#emdH5_FM_anc_2000"/>) separately <!-- ... --></p>
  <!-- In the play text: -->
  <l>Oh, <anchor xml:id="emdH5_FM_anc_2000"/>noble English,</l>
</div>
At build time, this will be expanded to (for example) (1.2.111). You will notice that we use the same mechanism for creating a point in the text that can be addressed as we do for annotations: we insert an anchor (see Encode Annotations for instructions on how to do that). To specify a range, include pointers to two anchors with a space between them:
<ptr type="localCit" target="doc:emdH5_FM.xml#emdH5_FM_anc_2000 doc:emdH5_FM.xml#emdH5_FM_anc_2001"/>
If you’re pointing at an entire line, speech, scene or act, then there’s no need to insert two anchors. You can instead add an @xml:id to the target element ( <l> , <sp> , or <div> , if there isn’t one there already, and point to that instead. To create a new @xml:id, the simplest way is to insert an anchor element in the usual way, then take its @xml:id, which is guaranteed to be unique, and use that, discarding the rest of the <anchor> .

Inline Processing Instructions in LEMDO

This documentation lists and explains a number of different custom processing instructions used by the LEMDO project to include content from elsewhere, and to trigger the automatic generation of content.
Processing for these PIs is specified in two places: first in the documentation_inclusion_master.xsl file, which handles the majority of cases since they occur mainly in documentation; but also in the xml_original_templates.xsl module, to handle any cases in which a PI may be used in a page which is not part of the documentation. These templates should be updated in a synchronized way.

Simple Inclusions

LEMDO prefers the use of processing instructions for the purposes of inclusion over other methods such as XInclude because it is more flexible; processing for XPointers in XInclude instructions is not widely supported, and some processors and validators may act upon XInclude instructions when they’re not intended to be processed. There are two PI-based inclusions in LEMDO:

lemdo-include

<?lemdo-include href="doc:learn_encodeLinks_intro"?>
This lemdo-include PI is used in the lemdo.odd file to assemble the separate documentation files found in the data/documentation folder into a single structured document before that is processed into the documentation web pages. This PI should not be used outside of the ODD file. See Documentation and the ODD File for more information.

lemdo-import

<?lemdo-import ref="doc:emdCAMP3_edition"?>
This lemdo-import PI is used in an anthology XML file to include an edition in the anthology. See LEMDO’s Build Process for more information.

Generating Content

Another set of processing instructions provides a way to generate content in an output page based on metadata or data elsewhere in the project. These are three examples:

category-listing

<?category-listing ref="emeeTheatre"?>
This tells the processor to find the <category> element in TAXO1 which whose @xml:id=emeeTheatre, and then to collect all documents which have <catRef> elements whose @target points at that category or any of its descendant categories. It then creates a list of links to those documents (a <list> element whose <item> s contain <ref> elements). This makes it possible to include an automatically-generated list of all the documents in a category wherever you need one.

taxonomy-table

<?taxonomy-table ref="emdAudiences"?>
This tells the processor to find the <taxonomy> element in TAXO1 which whose @xml:id=emdAudiences, and process it to create a TEI <table> element laying out all the categories and their definitions. That table is later processed into an HTML table in the documentation page for the site.

charDecl-table

<?charDecl-table ref="characters"?>
This tells the build process to generate a table from from character declarations ( <charDecl> elements) in TAXO1.

listPrefixDef-table

<?listPrefixDef-table ref="global_listPrefixDef"?>
This generates a table from a <listPrefixDef> , also in TAXO1.

roleList

<?roleList ref="emd1HW_M"?>
This generates a copy of any role lists encoded in the header of a text, in the form of <listPerson type="castlist"> elements. This can be used to create a separate page which incorporates copies of any role lists along with an introduction and comments, as a distinct component of an edition. Role lists are also available in the interface of the text which contains them, but it is often useful to provide more information as part of an edition.

msDesc

<?msDesc ref="emdDouai_AYL"?>
This generates a copy of any manuscript description ( <msDesc> ) encoded in the header of a text. This can be used to create a separate page which incorporates copies of the msDesc along with an introduction and comments, as a distinct component of an edition.

The staticSearch build process in LEMDO

This documentation explains how the staticSearch codebase is stored, updated, and used in build processes.

Introduction

LEMDO sites are static sites conformant with Endings principles, so they use the Endings-developed staticSearch system to provide search functionality for individual anthologies. Rather than check out a fresh copy of the staticSearch codebase every time we build something, we store a static copy of the codebase in our repository in code/search/staticSearch. This should be an up-to-date stable version of the codebase.

How staticSearch is used at build time

When any anthology is built, the staticSearch codebase is copied into a staticSearch folder in the anthology’s products directory. We could run all our staticSearch build indexing for all anthologies directly from the code/search/staticSearch folder, but making a copy enables us to do tests with alternative versions of staticSearch if we need to, using a single anthology.
For details on how staticSearch itself works, see the staticSearch documentation.

Keeping the staticSearch codebase updated

The file build_globals_module.xml contains a property called staticSearchBranch which specifies which branch we want to use for our staticSearch codebase copy. It should normally be set to a stable release branch, unless we are doing some unusual testing. Release branches are updated periodically, for bugfixes and minor enhancements, so there is also an Ant task in the same file called refreshStaticSearchCode, which will update the files in the code/search/staticSearch folder automatically. After running the update (ant -f build_globals_module.xml refreshStaticSearchCode), check the svn status of the code/search/staticSearch folder to see whether there are any new files that need to be added, or perhaps files that need to be deleted.

Witness List Processing

This documentation describes the process by which witness lists (TEI <listWit> and <witness> elements) are processed into output.

Witness Lists in the Source XML

The encoder documentation provides good info on how witnesses should be encoded. A <listWit> appears in the <sourceDesc> of a collation file, accompanying the apparatus list which is encoded in the body of the document. Each <witness> element represents a single source text which was used by the editor in creating the collation.
A Schematron rule constrains the <witness> element such that it either has @corresp and is itself empty, or has a tagged prose description of the witness and does not have @corresp. The first scenario is used when the BIBL1 entry pointed at by @corresp provides sufficient information and no further explanation is needed. In the second case, the editor provides a prose description which is more elaborate, but is expected to link some of the contents of that description to one or more entries in BIBL1.

Processing of Witness Lists

Witness lists are part of collations, and stored in collation files, but the build process that creates a fully-realized text combines the text of the work with the collations to produce an integrated whole. During the generation of standalone XML, the <listWit> is first copied into the play source file (always a modern edition). At that point, if a <witness> element is empty and it has @corresp, the target bibl element is copied into the content of the witness (minus its @xml:id), and the @corresp attribute is removed.
At the HTML stage, the witness list is processed into a sequence of <div> elements in the appendix of the document, along with the bibliography items, person elements and so on. These elements are hidden by CSS and shown only in response to user actions such as clicking on a linked name. Apparatus elements are also part of the appendix. When a user clicks on a collation icon, the relevant apparatus item appears in a popup. In that popup, each collation siglum is a link to its witness element, and clicking on that link causes the JavaScript to retrieve the witness info and append it to the bottom of the popup. Thus the detailed witness info is always available from any apparatus popup.

Print Editions

LEMDO publishes print editions of some of its modernized texts. This section of the documentation is intended to cover how those print editions are generated, and is aimed primarily at programmers, since it’s unlikely that anyone other than programmers will venture into this part of the codebase.

Requirements for Building Print Editions

The print editions are generated using LaTeX, and specifically the Xelatex compiler, so anyone wanting to generate a print edition will need to have not only Ant and ant-contrib but also the (substantial) LaTeX codebase installed. On Linux, we recommend installing the texlive-full package, which should include everything you need. On Mac, you can use the mactex distro. You can also install texlive on Windows, but we do not expect most of our build processes to work on Windows for a variety of reasons. *NIX-based OSes are a much better bet. The distributions are large, so don’t install this stuff just for fun; only do it if you have a need to build PDFs for print.
The PDF build file includes a quick check for the availability of the Xelatex compiler, so starting from the repository root, you can do this:
Change directories into the PDF build directory:
cd code/pdf
Run the check task:
ant checkForXelatex
If this works, you’re probably OK, although it’s always possible that a particular package required by the build process is not installed. If that’s the case, when you try to run a build, you should see helpful error messages from LaTeX.
All other requirements (specifically, the fonts used to build the PDF) should be in the repository.

Codebase for Building Print Editions

As you might expect, the codebase for building a print edition lives in code/pdf. It is basically very simple:
build.xml, the Ant build file.
Several XSLT files, in the xsl directory, of which the root file is latex_master.xsl. These files are inadequately organized at the time of writing, because they have developed as part of a learning process; when there is time, they will be reorganized. The content should be well-commented, though.
A fonts folder, in which there are two open-source fonts, Vollkorn and Josefin-Sans. These are configured respectively as the main font and the sans font for the PDF build.
A README file and a TODO file, which are essentially ad-hoc notes.

How to Build a Print Edition

Once you have ensured that your system is set up with all the requirements, and you have set up your TEI print edition document, you’re ready to try a build. Starting from the LEMDO repository root, this is what you do:
Change directories into the PDF build directory:
cd code/pdf
Run the build process, supplying the ID of the document you want to build:
ant -DdocsToBuild=emdOth_Print
(You can supply multiple IDs, comma-separated, if you want to.)
The build process will create a folder called pdf inside the main folder of the text you are building. In there, a number of files will be saved, including a log file, the .tex file containing the LaTeX code which is generated and then compiled, and the PDF file of the print edition. If anything goes wrong, you should see either helpful messages from our code or mysterious messages from the LaTeX compiler.
During the build process you will see many very puzzling emanations such as the common Underfull \hbox (badness 1033) message from the compiler. These are mostly informational, warning you when the layout engine has had to stretch or squash a line a little more than it would like to in order to get the justification to work. However, if the build actually fails, you will need to pay attention to whatever message coincides with the termination of the build.
You will notice that the Xelatex compiler is run at least four times on the .tex file. This is because at each run, the layout engine is able to do a slightly better job of adjusting spacing, pagination and so on, but every time it does this, page references and similar content which were generated at the time of the previous build are potentially no longer accurate, so another run is recommended. The number of runs required to get a final version is not easy to determine, so we run four times by default, but this may need to be adjusted.

Print Edition XML Files

A LEMDO print edition is established by creating a standard LEMDO TEI file, but with a filename ending in _Print.xml. This should be created in the main folder of the work itself. So for example, if you’re creating a print edition of Othello, you would create this file: data/texts/Oth/main/emdOth_Print.xml
This file is like any other TEI text in the project; it has metadata, responsibility statements and so on. But it will mostly consist of content from other parts of the edition directory. Primarily, it will include a modern-spelling edition of the play, but it will also have other components such as critical materials and a bibliography. The following is a simplified example which will be explained below, and should cover all the main components.
<TEI version="5.0" xml:id="emdOthX_Print">
  <teiHeader> [Normal metadata should appear here...] <textClass>
    <catRef scheme="tax:emdDocumentTypes" target="cat:ldtBornDigPrint"/>
  </textClass> [More metadata...] </teiHeader>
  <text>
    <text>
      <front>
        <linkGrp type="printInclude">
          <ptr target="doc:emdOth_TextIntro"/>
        </linkGrp>
      </front>
      <body>
        <div>
          <linkGrp type="printInclude">
            <ptr target="doc:emdOth_M#emdOth_M_castList"/>
            <ptr target="doc:emdOth_M"/>
          </linkGrp>
        </div>
      </body>
      <back>
        <div>
          <divGen type="bibliography"/>
          <linkGrp type="printInclude">
            <ptr target="doc:emdOth_M_annotation"/>
          </linkGrp>
        </div>
      </back>
    </text>
  </text>
</TEI>
The header is a normal header except for the particular document type specified with <catRef> /@target="cat:ldtBornDigPrint".
But in <text> , the first thing you will notice is that the <front> , <body> and <back> elements do not include any content directly. They can include content if necessary, and there may well be components that are intended to be used only for one particular print edition, and therefore belong directly in this file, but most content is in the form of <linkGrp> elements containing pointers. These pointers specify other files in the repository, or sections of files. They use the doc: prefix to point to the ids of files, and an optional fragment identifier to point to a specific part of the file. These includes will be processed by the first stage of the build code to create a complete TEI file incorporating all these components. That structure will then be processed into the TEI file.
Notice the organization: critical materials come in the <front> element, the castlist and the play itself come in the <body> , and the bibliography (of which more below) appears in the <back> . Also in the <back> are any annotation files which are needed; these are processed into footnotes at build time. Only annotations which are actually referenced in the included texts will be used, and the rest will be discarded.
Finally, note the special case of the <divGen> element for the bibliography. This is acted on by the build code, which retrieves from BIBL1.xml all bibliography items which are actually mentioned in the rest of the content, and generates a bibliography from them automatically. Note that if there is a reference to an item which does not appear in BIBL1.xml, the PDF build will fail and stop.

Special Encoding for Print Editions

A print edition is normally built from regular edition files and supplementary materials, but there are a few cases in which special encoding may be required. Some of these are covered in Remediate Annotations for Print, Encode Annotations, and Types of Annotations.
One feature of print editions is the Table of Contents which is automatically generated at build time from the contents of the combined print document. This is constructed from all the <head> elements that appear in the text. However, sometimes it is desirable not to include a particular heading as an entry in the table of contents (where, for example, a short section or chapter has a lot of headings which would all be listed as being on the same page). In this case, you can add @type to the <head> element as in this example:
<head type="noTOC">How to navigate and cite</head>
If you do this, the <head> element will be ignored when creating the Table of Contents for the print volume.

Documentation and the ODD File

Introduction

This file explains the relationship between documentation files and the project’s ODD file. It provides a quick and general overview of the files involved in the corresponding processes, and then describes the processes in general, without too much attention to the technical details.

Relevant Code Files

Below is a list of code files stored in lemdo/code/site/xsl/documentation, responsible for generating and processing documentation files, along with their role in the process.
documentation_inclusion_master.xsl: Adds the content from the individual documentation files rooted on divs into the ODD file.
documentation_to_documentation_chapters_master.xsl: Creates the chapter as determined by the corresponding <div> element and the value of its @xml:id attribute in the body of ODD. The chapter contains sections.
documentation_to_documentation_sections_master.xsl: Creates the sections by adding them via a process of ?lemdo-include that specifies the names of the individual files (stored in data/documentation).
documentation_to_elements_master.xsl: Extracts the elements ( <div> [ @type=refdoc]) in lemdo.lite.odd into their separate files. In the odd file we add element abstracts to the elementSpec as needed. These are added in <remark> elements, unless we want to replace the TEI desc, then we add <desc> elements with @mode attribute whose value is replace.
lemdo_extract_egXMLs_master.xsl
lemdo_extract_rules.xsl: Extracts the rules from the schema that is written and developed in the ODD file

Processes

We write our documentation in files that are rooted on <div> elements and we store them in the lemdo/data/documentation folder. These files are then included in the ODD file via processing instructions and a series of XSL transformations. Every chapter is a <div> in the body of the ODD file, and every <div> includes a series of processing instructions that are later processed into the sections (pages) of a certain chapter. The sections are the files from data/documentation. The chapters are generated programmatically, as instructed per the ODD file. This process happens through the XSL files as described above.
The documentation_to_documentation_chapters_master.xsl file is also responsible for creating the documentation index, from the chapter <div> s as they are laid out in the lemdo.lite.odd stage of the documentation creation process. While the chapter titles (Chapter 1. Quickstart Guidelines, etc.) are determined in the odd file, the section headers are determined in the <head> child element of the root <div> element in the corresponding documentation file.
Please see for detailed guidelines. We write the documentation with a root <div> element so that we can append the file content to the LEMDO ODD file as we generate it. From the ODD file we then grab corresponding <div> s and create the proper structure for them, adding header and body elements. This process begins with the documentation_inclusion_master.xsl, which includes the <div> elements in the LEMDO ODD file, as instructed by a series of processing instructions. The documentation_to_documentation_chapters_master.xsl and documentation_to_documentation_sections_master.xsl files process the documentation <div> elements from the LEMDO TEI Lite ODD file and make them into their own standalone files, in XML as well as HTML.
All of the above happens automatically as part of the build process. However, you may want to test your documentation locally, in XML or HTML. To build XML files, go to code/build_documentation_master.xsl, and press the play button. The files are outputted in lemdo/chapters_out and lemdo/sections_out. To locally build your documentation files into html files, open Terminal and type the following command: ant createDocumentation. You can find more on local builds in Run Local Builds.

Adding Element Notes and Replacing TEI Abstracts

In LEMDO, element documentation is generated directly as imported from the TEI P5 Guidelines. Given the nature of the project and the specialized uses for TEI elements, LEMDO adds notes and modifies TEI abstracts where necessary. This process is accomplished in the <elementSpec> elements of the corresponding element in the ODD file. To add a note to the existing element structure and descriptions, follow these steps:
Find the element you want to change by searching for it using command + F (for Mac users) or Ctrl + F (For Windows and Linux users)
Add a @mode attribute with the value change
Add the element you want to replace
To replace the <gloss> or <desc> elements and their content, add the element you want to replace and give it a @mode attribute and the value change
Write your content between the opening and closing tags
Note that the <gloss> and <desc> elements and their original TEI content are not present in the ODD file, they are automatically imported from the TEI guidelines at processing time. If you would like to add a note to the existing TEI descriptions, follow these steps:
In <elementSpec> , add a <remarks> element with a @mode attribute and a value add
Write your note in <p> elements inside of <remarks>
Your note will appear in the table of specs on the element’s page on the LEMDO site, with the label Note.

Prosopography

Illya

Illya has a BA in English and Sociocultural Anthropology and an MA in English. Prior to joining the HCMC, he was a PhD candidate in English and Book History at the University of Toronto and worked on Records of Early English Drama and on the Modernist Archives Publishing Project. His work at the HCMC focuses on creating web-based applications for research projects led by members of the faculty of Humanities at the University of Victoria. This involves creating schemas for new and existing datasets, writing XSLT and build files to transform datasets into structured TEI and HTML formats, implementing staticSearch, and ensuring that new projects are Endings Principles compliant.

Isabella Seales

Isabella Seales is a fourth year undergraduate completing her Bachelor of Arts in English at the University of Victoria. She has a special interest in Renaissance and Metaphysical Literature. She is assisting Dr. Jenstad with the MoEML Mayoral Shows anthology as part of the Undergraduate Student Research Award program.

Janelle Jenstad

Janelle Jenstad is a Professor of English at the University of Victoria, Director of The Map of Early Modern London, and Director of Linked Early Modern Drama Online. With Jennifer Roberts-Smith and Mark Beatrice Kaethler, she co-edited Shakespeare’s Language in Digital Media: Old Words, New Tools (Routledge). She has edited John Stow’s A Survey of London (1598 text) for MoEML and is currently editing The Merchant of Venice (with Stephen Wittek) and Heywood’s 2 If You Know Not Me You Know Nobody for DRE. Her articles have appeared in Digital Humanities Quarterly, Elizabethan Theatre, Early Modern Literary Studies, Shakespeare Bulletin, Renaissance and Reformation, and The Journal of Medieval and Early Modern Studies. She contributed chapters to Approaches to Teaching Othello (MLA); Teaching Early Modern Literature from the Archives (MLA); Institutional Culture in Early Modern England (Brill); Shakespeare, Language, and the Stage (Arden); Performing Maternity in Early Modern England (Ashgate); New Directions in the Geohumanities (Routledge); Early Modern Studies and the Digital Turn (Iter); Placing Names: Enriching and Integrating Gazetteers (Indiana); Making Things and Drawing Boundaries (Minnesota); Rethinking Shakespeare Source Study: Audiences, Authors, and Digital Technologies (Routledge); and Civic Performance: Pageantry and Entertainments in Early Modern London (Routledge). For more details, see janellejenstad.com.

Joey Takeda

Joey Takeda is LEMDO’s Consulting Programmer and Designer, a role he assumed in 2020 after three years as the Lead Developer on LEMDO.

Mahayla Galliford

Project Manager, 2025-present; Assistant Project Manager, 2024-2025; Research Assistant, 2021-present. Mahayla Galliford (she/her) graduated from the University of Victoria with a BA (honours with distinction) in 2024, and an MA English in 2026. Mahayla’s undergraduate research explored early modern stage directions and civic water pageantry. Her SSHRC-funded MA thesis project focuses on transcribing, editing, and encoding early modern girls’ manuscripts, specifically Lady Rachel Fane’s May Masque in collaboration with LEMDO.

Martin Holmes

Martin Holmes has worked as a developer in the UVic’s Humanities Computing and Media Centre for over two decades, and has been involved with dozens of Digital Humanities projects. He has served on the TEI Technical Council and as Managing Editor of the Journal of the TEI. He took over from Joey Takeda as lead developer on LEMDO in 2020. He is a collaborator on the SSHRC Partnership Grant led by Janelle Jenstad.

Navarra Houldin

Training and Documentation Lead 2025–present. LEMDO project manager 2022–2025. Textual remediator 2021–present. Navarra Houldin (they/them) completed their BA with a major in history and minor in Spanish at the University of Victoria in 2022. Their primary research was on gender and sexuality in early modern Europe and Latin America. They are continuing their education through an MA program in Gender and Social Justice Studies at the University of Alberta where they will specialize in Digital Humanities.

Samuel Seaberg

Samuel Seaberg, a University of Victoria English undergrad, enjoys riding his bike. During the summer of 2025, he began working with LEMDO as a recipient of the Valerie Kuehne Undergraduate Research Award (VKURA). Unfortunately, due to his summer being spent primarily in working to establish an edition of Thomas Heywood’s If You Know Not Me, You Know Nobody, Part 2 and consequently working out how to represent multi-text works in a digital space, his bike has suffered severely of sheltered seclusion from the sun. Note: Samuel now works for LEMDO as the Assistant Project Manager, much to his bike’s chagrin.

Tracey El Hajj

Junior Programmer 2019–2020. Research Associate 2020–2021. Tracey received her PhD from the Department of English at the University of Victoria in the field of Science and Technology Studies. Her research focuses on the algorhythmics of networked communications. She was a 2019–2020 President’s Fellow in Research-Enriched Teaching at UVic, where she taught an advanced course on Artificial Intelligence and Everyday Life. Tracey was also a member of the Map of Early Modern London team, between 2018 and 2021. Between 2020 and 2021, she was a fellow in residence at the Praxis Studio for Comparative Media Studies, where she investigated the relationships between artificial intelligence, creativity, health, and justice. As of July 2021, Tracey has moved into the alt-ac world for a term position, while also teaching in the English Department at the University of Victoria.

Bibliography

OED: The Oxford English Dictionary. 2nd ed. Oxford University Press, 1989.

Metadata