MilestoneXSLT

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

 Give me then your house &amp; Grounds  I ask for nothing else 

Script 2: splitting elements, then expanding milestones

 Card room where  nine out of ten had no inclination 

Script 3: looping on textual nodes

   For James Edward Austen  Jane Austen May 6th 1792 

Expected Output
Script 1

the function would produce the following XML fragment as output:  <lb>Give me then your house &amp; Grounds</w></lb> <lb>I ask for nothing else</lb> </TEI>

Script 2

 <lb> <del rend=”overstrike”>Card room where </lb><lb> <del rend=”overstrike”>nine out of ten had no inclination </lb> </TEI>

Script 3

<div class=”pb”>blvolthird-03” <span class=”pencil”>For James Edward Austen <span class=”default”>Jane Austen May 6 <span class=”default”>th <span class=”default”>1792

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|@*">        <xsl:copy>            <xsl:apply-templates select="node|@*"/>        </xsl:copy>    </xsl:template>    <xsl:template match="p">        <xsl:variable name="cur-p" select="generate-id(.)"/>        <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> </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"> <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]]"/>

<lb> <xsl:sequence select="@*"/> </lb>

<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]]"/> </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"> <xsl:apply-templates mode="step2"/> </xsl:template>

<xsl:template match="p" mode="step2"> <xsl:variable name="cur-p" select="generate-id(.)"/> <xsl:choose> <xsl:when test="exists(descendant::lb)"> <xsl:for-each select="descendant::lb"> <xsl:variable name="cur-lb" select="generate-id(.)"/> <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> <xsl:if test="not(following::lb[parent::p[generate-id=$cur-p]])"> <xsl:for-each select="following::*[ancestor::p[generate-id=$cur-p]]"> <xsl:apply-templates select="." mode="step2"/> </xsl:for-each> </xsl:if> </xsl:for-each> </xsl:when> <xsl:otherwise> <xsl:apply-templates mode="step2"/> </xsl:otherwise> </xsl:choose> </xsl:template>

<xsl:template match="del" mode="step2"> <xsl:apply-templates mode="step2"/> </xsl:template>

<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"> <xsl:apply-templates mode="step2"/> </xsl:template>

<xsl:template match="p" mode="step2"> <xsl:variable name="cur-p" select="generate-id(.)"/> <xsl:choose> <xsl:when test="exists(descendant::lb)"> <xsl:for-each select="descendant::lb"> <xsl:variable name="cur-lb" select="generate-id(.)"/> <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>

<xsl:if test="not(following::lb[parent::p[generate-id=$cur-p]])"> <xsl:for-each select="following::*[ancestor::p[generate-id=$cur-p]]"> <xsl:apply-templates select="." mode="step2"/> </xsl:for-each> </xsl:if>

</xsl:for-each> </xsl:when> <xsl:otherwise> <xsl:apply-templates mode="step2"/> </xsl:otherwise> </xsl:choose> </xsl:template>

<xsl:template match="handShift" mode="step2"> <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"/> </xsl:template>

<xsl:template match="/"> <xsl:sequence select="$step2"/> </xsl:template>

</xsl:stylesheet>