MilestoneXSLT
Contents
Authorship
Author | Raffaele Viglianti and Elena Pierazzo, King’s College London, raffaele.viglianti@kcl.ac.uk elena.pierazzo@kcl.ac.uk |
Last revised | 2008-06-23 |
Previous version | none |
Summary
This is a group of XSLT scripts for managing milestones (page breaks, line breaks, hand shifts, etc.) in XSLT 2.0 (but can work also in 1.0, see below). These scripts are part of a poster presented at DH2008 by Elena Pierazzo and Raffaele Viglianti: XSLT (2.0) handbook for processing multiple hierarchies. Three different approaches are presented, ordered by complexity of the input and of the script as well.
Required Input
Script 1: expanding milestones
<TEI> <text> <body> <p> Give me then your house & <w>Grounds</w> <lb/> I ask for nothing else </p> </body> </text> </TEI>
Script 2: splitting elements, then expanding milestones
<TEI> <text> <body> <p> <del rend=”overstrike”>Card room where <lb/> nine out of ten had no inclination</del> </p> </body> </text> </TEI>
Script 3: looping on textual nodes
<TEI> <text> <body> <pb xml:id=”blvolthird-03”/> <div> <p><handShift new=”#a2”/> For James Edward Austen</p> </div> <div> <p><handShift new=”#a2”/> Jane Austen May 6<hi rend=”sup”>th</hi> 1792</p> </div> </body> </text> </TEI>
Expected Output
Script 1
the function would produce the following XML fragment as output:
<TEI> <text> <body> <p> <lb>Give me then your house & <w>Grounds</w></lb> <lb>I ask for nothing else</lb> </p> </body> </text> </TEI>
Script 2
<TEI> <text> <body> <p> <lb> <del rend=”overstrike”>Card room where</del> </lb><lb> <del rend=”overstrike”>nine out of ten had no inclination</del> </lb> </p> </body> </text> </TEI>
Script 3
<html> <body> <div class=”pb”>blvolthird-03”</div> <div> <p><span class=”pencil”>For James Edward Austen</span></p> </div> <div> <p> <span class=”default”>Jane Austen May 6</span><sip><span class=”default”>th</span></sup> <span class=”default”>1792</span></p> </div> </body> </html>
Known Restrictions or Problems
The code shown below requires XSLT 2. With XSLT 1 it is possible to emulate the “step” approaches by using more than one script and intermediate files
The running time is very similar using a standalone saxon process or embedded in Apache Cocoon
Code
Script 1
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" xpath-default-namespace="http://www.tei-c.org/ns/1.0" xmlns:tei="http://www.tei-c.org/ns/1.0"> <xsl:output method="xml" indent="yes" encoding="UTF-8”/> <xsl:template match="node()|@*"> <!-- Copy the current node --> <xsl:copy> <!-- Including any child nodes it has and any attributes --> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <xsl:template match="p"> <xsl:variable name="cur-p" select="generate-id(.)"/> <p><xsl:choose> <xsl:when test="lb"> <xsl:for-each select="lb"> <lb> <xsl:sequence select="parent::p/@*"/> <xsl:apply-templates select="preceding::*[parent::p[generate-id()=$cur-p]]|preceding::text()[parent::p[generate-id()=$cur-p]]"/> <xsl:apply-templates select="preceding::*/@*[parent::p[generate-id()=$cur-p]]"/> </lb> <lb> <xsl:sequence select="parent::p/@*"/> <xsl:sequence select="following::*[parent::p[generate-id()=$cur-p]]|following::text()[parent::p[generate-id()=$cur-p]]"/> <xsl:sequence select="following::*/@*[parent::p[generate-id()=$cur-p]]"/> </lb> </xsl:for-each> </xsl:when> <xsl:otherwise> <xsl:sequence select="."/> </xsl:otherwise> </xsl:choose> </p> </xsl:template> </xsl:stylesheet>
Script 2
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" xpath-default-namespace="http://www.tei-c.org/ns/1.0" xmlns="http://www.tei-c.org/ns/1.0"> <xsl:output method="xhtml" indent="yes" encoding="UTF-8" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"/> <xsl:strip-space elements="*"/> <xsl:variable name="step1"> <xsl:call-template name="one"/> </xsl:variable> <xsl:variable name="step2"> <xsl:apply-templates select="$step1" mode="step2"/> </xsl:variable> <xsl:template match="*" mode="step1"> <xsl:copy> <xsl:sequence select="@*"/> <xsl:apply-templates mode="step1"/> </xsl:copy> </xsl:template> <xsl:template match="del" mode="step1"> <xsl:variable name="cur-del" select="generate-id(.)"/> <xsl:choose> <xsl:when test="lb"> <xsl:for-each select="lb"> <del> <xsl:choose> <xsl:when test="parent::del/@type"> <xsl:variable name="type" select="generate-id(parent::del/@type)"/> <xsl:sequence select="parent::del/@*[generate-id() != $type]"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="parent::del/@*"/> </xsl:otherwise> </xsl:choose> <xsl:apply-templates select="preceding::*[parent::del[generate-id()=$cur-del]]|preceding::text()[parent::del[generate-id()=$cur-del]]"/> <xsl:apply-templates select="preceding::*/@*[parent::del[generate-id()=$cur-del]]"/> </del> <lb> <xsl:sequence select="@*"/> </lb> <del> <xsl:sequence select="parent::del/@*"/> <xsl:sequence select="following::*[parent::del[generate-id()=$cur-del]]|following::text()[parent::del[generate-id()=$cur-del]]"/> <xsl:sequence select="following::*/@*[parent::del[generate-id()=$cur-del]]"/> </del> </xsl:for-each> </xsl:when> <xsl:otherwise> <xsl:sequence select="."/> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template name="one"> <xsl:apply-templates select="TEI" mode="step1"/> </xsl:template> <xsl:template match="/" mode="step2"> <html> <body> <xsl:apply-templates mode="step2"/> </body> </html> </xsl:template> <xsl:template match="p" mode="step2"> <xsl:variable name="cur-p" select="generate-id(.)"/> <p> <xsl:choose> <xsl:when test="exists(descendant::lb)"> <xsl:for-each select="descendant::lb"> <xsl:variable name="cur-lb" select="generate-id(.)"/> <span class="line"> <xsl:for-each select="preceding::node()[ancestor::p[generate-id()=$cur-p]]"> <xsl:choose> <xsl:when test="not(self::lb)"> <xsl:if test="generate-id(following::lb[1])=$cur-lb and generate-id(parent::node()[1])=$cur-p"> <xsl:apply-templates select="." mode="step2"/> </xsl:if> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="." mode="step2"/> </xsl:otherwise> </xsl:choose> </xsl:for-each> </span> <xsl:if test="not(following::lb[parent::p[generate-id()=$cur-p]])"> <span class="line"> <xsl:for-each select="following::*[ancestor::p[generate-id()=$cur-p]]"> <xsl:apply-templates select="." mode="step2"/> </xsl:for-each> </span> </xsl:if> </xsl:for-each> </xsl:when> <xsl:otherwise> <xsl:apply-templates mode="step2"/> </xsl:otherwise> </xsl:choose> </p> </xsl:template> <xsl:template match="del" mode="step2"> <del> <xsl:apply-templates mode="step2"/> </del> </xsl:template> <!-- OUTPUTTING --> <xsl:template match="/"> <xsl:sequence select="$step2"/> </xsl:template> </xsl:stylesheet>
Script 3
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" xpath-default-namespace="http://www.tei-c.org/ns/1.0" xmlns="http://www.tei-c.org/ns/1.0"> <xsl:output method="xhtml" indent="yes" encoding="UTF-8" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"/> <xsl:strip-space elements="*"/> <xsl:variable name="step1"> <xsl:call-template name="one"/> </xsl:variable> <xsl:variable name="step2"> <xsl:apply-templates select="$step1" mode="step2"/> </xsl:variable> <xsl:template match="*" mode="step1"> <xsl:copy> <xsl:sequence select="@*"/> <xsl:apply-templates mode="step1"/> </xsl:copy> </xsl:template> <xsl:template match="text()[not(ancestor::teiHeader)]" mode="step1"> <handShift> <xsl:sequence select="preceding::handShift[1]/@new"/> <xsl:value-of select="."/> </handShift> </xsl:template> <xsl:template match="handShift" mode="step1"/> <xsl:template name="one"> <xsl:apply-templates select="TEI" mode="step1"/> </xsl:template> <xsl:template match="/" mode="step2"> <html> <body> <xsl:apply-templates mode="step2"/> </body> </html> </xsl:template> <xsl:template match="p" mode="step2"> <xsl:variable name="cur-p" select="generate-id(.)"/> <p> <xsl:choose> <xsl:when test="exists(descendant::lb)"> <xsl:for-each select="descendant::lb"> <xsl:variable name="cur-lb" select="generate-id(.)"/> <span class="line"> <xsl:for-each select="preceding::node()[ancestor::p[generate-id()=$cur-p]]"> <xsl:choose> <xsl:when test="not(self::lb)"> <xsl:if test="generate-id(following::lb[1])=$cur-lb and generate-id(parent::node()[1])=$cur-p"> <xsl:apply-templates select="." mode="step2"/> </xsl:if> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="." mode="step2"/> </xsl:otherwise> </xsl:choose> </xsl:for-each> </span> <xsl:if test="not(following::lb[parent::p[generate-id()=$cur-p]])"> <span class="line"> <xsl:for-each select="following::*[ancestor::p[generate-id()=$cur-p]]"> <xsl:apply-templates select="." mode="step2"/> </xsl:for-each> </span> </xsl:if> </xsl:for-each> </xsl:when> <xsl:otherwise> <xsl:apply-templates mode="step2"/> </xsl:otherwise> </xsl:choose> </p> </xsl:template> <xsl:template match="handShift" mode="step2"> <span> <xsl:attribute name="class"> <xsl:choose> <xsl:when test="@new= '#a2'"> <xsl:text>default</xsl:text> </xsl:when> <xsl:when test="@new='#a1'"> <xsl:text>pencil</xsl:text> </xsl:when> </xsl:choose> </xsl:attribute> <xsl:apply-templates mode="step2"/> </span> </xsl:template> <!-- OUTPUTTING --> <xsl:template match="/"> <xsl:sequence select="$step2"/> </xsl:template> </xsl:stylesheet>