<?xml-stylesheet href="http://www.w3.org/StyleSheets/base.css" type="text/css"?>
<?xml-stylesheet href="http://www.w3.org/2002/02/style-xsl.css" type="text/css"?>
<?xml-stylesheet href="http://www.w3.org/2002/07/01-style-xsl.xsl" type="application/xml"?>
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:html="http://www.w3.org/1999/xhtml" xmlns="http://www.w3.org/1999/xhtml" exclude-result-prefixes="html" xmlns:saxon="http://icl.com/saxon" extension-element-prefixes="saxon">
  <!--
       This XSLT turns an XHTML document with well-identified parts into a set of XHTML pages (one page per part); a part is identified by &lt;div class="part"&gt; in the code, must starts with an h2..
       It uses the saxon:output extension
       -->

  <!-- Output method for XHTML -->
  <xsl:output method="xml" 
    indent="yes"
    omit-xml-declaration="no" 
    encoding="ISO-8859-1" 
    doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
    doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"/>

    <html xmlns="http://www.w3.org/1999/xhtml">
      <head>
        <link rel="stylesheet" href="http://www.w3.org/StyleSheets/base"/>
        <title>XHTML document splitter</title>
      </head>
      <body>
    <p><a href="/"><img src="/Icons/w3c_home" alt="W3C"/></a></p>
    <h1>XHTML document splitter</h1>
    <p>This XSLT takes an XHTML document formatted with the conventions described below and splits it in several pages; it requires the <code>saxon:output</code> extension to work.</p>
    <h2>Conventions</h2>
    <p>The XSLT divides the document based on parts marked up as &lt;div class='part'&gt;; the title of the said part is expected in a &lt;h2&gt; level heading.</p>
    <h2>Features</h2>
    <ul>
      <li>the filenames for each of the pages are computed either from the id put in the &lt;h2> heading or as 'part-<param>number</param>.html', where <param>number</param> is the position of the part in the initial document</li>
      <li>a navigation bar is added at the top and the bottom of each of the pages to go to the previous/next page</li>
      <li>internal links are adapted to the new division</li>
      <li>headings levels are adapted to the new division</li>
    </ul>

    <p>Feedback, requests for enhancement and bug reports are welcomed.</p>
    <address><a href="http://www.w3.org/People/Dom/">Dominique Haza&#235;l-Massieux</a> - $Id: divide-doc.xsl,v 1.2 2003/12/15 10:28:10 dom Exp $</address>
  </body>
  </html>


  <xsl:template match="/">
    <xsl:apply-templates select="html:html/html:body//html:div[@class='part']"/>
  </xsl:template>

  <!-- default: Identity Transformation -->
  <xsl:template match="*|@*|comment()|text()">
    <xsl:copy>
      <xsl:apply-templates select="*|@*|comment()|text()"/>
    </xsl:copy>
  </xsl:template>




  <xsl:template match="html:div[@class='part']">
    <xsl:variable name="filename">
      <xsl:apply-templates select="." mode="filename"/>
    </xsl:variable>

    <saxon:output href="{$filename}" method="xml" indent="yes" omit-xml-declaration="no" encoding="ISO-8859-1" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN">
      <html xmlns="http://www.w3.org/1999/xhtml">
        <head>
          <xsl:apply-templates select="/html:html/html:head/*[not(local-name()='title' or local-name()='link')]"/>
          <xsl:choose>
            <!-- For any part which is not the 1st one, we change the title to say that this is a part in a set of page -->
            <xsl:when test="preceding::html:div[@class='part']">
              <xsl:variable name="firstPart">
                <xsl:apply-templates select="/html:html/html:body//html:div[@class='part'][1]" mode="filename"/>
              </xsl:variable>
              <title><xsl:value-of select="substring-after(descendant::html:h2[1],'. ')"/> - Part <xsl:value-of select="substring-before(//html:h2,'. ')"/> in <xsl:value-of select="/html:html/html:head/html:title"/></title>
              <link rel='start' href='{$firstPart}' title='{/html:html/html:head/html:title} Cover Page'/>
            </xsl:when>
            <!-- For the 1st part, we keep the same title as the main doc, and we keep (if it exists), the link rel='start' -->
            <xsl:otherwise>
              <xsl:apply-templates select="/html:html/html:head/html:title"/>
              <xsl:apply-templates select="/html:html/html:head/html:link[@rel='start']"/>
            </xsl:otherwise>
          </xsl:choose>
          <!-- Adding contextual navigation links using the <link/> mechanism -->
          <xsl:call-template name="navlinks2">
            <xsl:with-param name="type" select="'link'"/>
          </xsl:call-template>
          <!-- Moving the other links to match the new division -->
          <xsl:apply-templates select="/html:html/html:head/html:link[@rel and not(@rel='start' or @rel='next' or @rel='prev')]" mode="move"/>
        </head>
        <body xml:lang="en" lang="en">
          <!-- This template addes visible navigational links -->
          <xsl:call-template name="navlinks"/>
          <!-- the headings needs to be moved up from 1 level, and the internal links needs to be modified -->
          <xsl:apply-templates select="*" mode="move"/>
          <xsl:call-template name="navlinks"/>
        </body>
      </html>
    </saxon:output>
  </xsl:template>

  <!-- Computes the filename used for a given part -->
  <xsl:template match="html:div[@class='part']" mode="filename">
    <xsl:choose>
      <xsl:when test="descendant::html:h2[1]//html:a/@id">
        <xsl:value-of select="concat(descendant::html:h2[1]//html:a[@id][1]/@id,'.html')"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="concat('part-',count(preceding::html:div[@class='part']) + 1,'.html')"/>
      </xsl:otherwise>
    </xsl:choose>    
  </xsl:template>

  <!-- Navigational links -->
  <xsl:template name="navlinks">
    <div class="navlinks">
      <p>
        <xsl:call-template name="navlinks2">
          <xsl:with-param name="type" select="'a'"/>
        </xsl:call-template>
      </p>
    </div>
  </xsl:template>

  <!-- This template creates links (either using <a/> or <link/> depending on the paramters) to links the different subparts one with another -->
  <xsl:template name="navlinks2">
    <xsl:param name="type" select="'a'"/>
    <xsl:variable name="prevPart">
      <xsl:apply-templates select="preceding::html:div[@class='part'][position()=1]" mode="filename"/>
    </xsl:variable>
    <xsl:variable name="nextPart">
      <xsl:apply-templates select="following::html:div[@class='part'][position()=1]" mode="filename"/>
    </xsl:variable>
    <xsl:choose>
      <xsl:when test="not(preceding-sibling::html:div[@class='part'])">
        <xsl:if test="$type='a'">
        [ previous ]          
        </xsl:if>
      </xsl:when>
    </xsl:choose>
    <xsl:call-template name="formatLink">
      <xsl:with-param name="type" select="$type"/>
      <xsl:with-param name="rel" select="'prev'"/>
      <xsl:with-param name="href" select="$prevPart"/>
      <xsl:with-param name="title" select="'previous'"/>
    </xsl:call-template>
    <xsl:choose>
      <xsl:when test="position()=last()">
        <xsl:if test="$type='a'">
          [ next ]
        </xsl:if>
      </xsl:when>
      <xsl:otherwise>
        <xsl:call-template name="formatLink">
          <xsl:with-param name="type" select="$type"/>
          <xsl:with-param name="rel" select="'next'"/>
          <xsl:with-param name="href" select="$nextPart"/>
          <xsl:with-param name="title" select="'next'"/>
        </xsl:call-template>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- Format links as <a href=""/> or <link href=""/> depending on the param -->
  <xsl:template name="formatLink">
    <xsl:param name="type" select="'a'"/>
    <xsl:param name="rel"/>
    <xsl:param name="href"/>
    <xsl:param name="title"/>
    <xsl:choose>
      <xsl:when test="$type='a'">
        [ <a href="{$href}" rel="{$rel}"><xsl:value-of select="$title"/></a> ]
      </xsl:when>
      <xsl:otherwise>
        <link rel="{$rel}" href="{$href}" title="{$title}"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- Moving stuff around -->
  <!-- By default, nothing -->
  <xsl:template match="*|@*|comment()|text()" mode="move">
    <xsl:copy>
      <xsl:apply-templates select="*|@*|comment()|text()" mode="move"/>
    </xsl:copy>
  </xsl:template>
  
  <!-- the headings are pushed up (except in the 1st part) -->
  <xsl:template match="html:*[starts-with(local-name(),'h')]" mode="move">
    <xsl:variable name="level" select="substring-after(local-name(),'h')"/>
    <xsl:choose>
      <xsl:when test="not(ancestor::html:div[@class='part']//preceding::html:div[@class='part']) and $level &gt; 1">
        <xsl:element name="{concat('h',$level - 1)}">
          <xsl:apply-templates select="*|@*|comment()|text()" mode="move"/>
        </xsl:element>
      </xsl:when>
      <xsl:otherwise>
        <xsl:copy>
          <xsl:apply-templates select="*|@*|comment()|text()" mode="move"/>
        </xsl:copy>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- internal links are re-targetted -->
  <xsl:template match="html:a[starts-with(@href,'#')]|html:link[starts-with(@href,'#')]" mode="move">
    <xsl:variable name="target" select="@href"/>
    <xsl:variable name="targetPart">
      <xsl:apply-templates select="/html:html//html:a[@name=substring-after($target,'#')]/ancestor::html:div[@class='part']" mode="filename"/>
    </xsl:variable>
    <xsl:copy>
      <xsl:attribute name="href">
        <xsl:value-of select="concat($targetPart,$target)"/>
      </xsl:attribute>
      <xsl:apply-templates select="@*[not(local-name()='href')]|*|comment()|text()" mode="move"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>