<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Copyright 2002-2007 DeltaXML Ltd. All rights reserved.
     $Id: docbook-infilter.xsl 4502 2008-06-06 10:26:02Z nigelw $

This stylesheet processes a docbook document to add keys and divide text in
some elements into lines so that a line-by-line comparison is done. 

Using this stylesheet to process docbook files before they are compared with DeltaXML
Markup will enable docbook files to be compared intelligently. The filter also
converts all ID attributes to keys so these are used to 'line up' corresponding items 
in the two files.

This code is offered as an example and may not be correct for handling all docbook files.
-->

<!-- Define the docbook and deltaxml: namespace and prefixes for the stylesheet 
     The docbook namespace may need to be changed for a different version of docbook -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                xmlns:deltaxml="http://www.deltaxml.com/ns/well-formed-delta-v1"
                version="1.0" >

  <xsl:param name="preserve-comments" select="false"/>

  <xsl:output method="xml" indent="no"/>

  <!-- identity transform by default -->
  <xsl:template match="* | text() | processing-instruction() | @*">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>
  
  <!-- fail if revisionflag attributes exist -->
  <xsl:template match="@revisionflag">
    <xsl:message terminate="yes">This document already contains revisionflag attributes and performing a comparison may not produce sensible results.
Please remove the revisionflag attributes and try again.</xsl:message>
  </xsl:template>

  <!-- Handle specific element types here -->

  <!-- Elements that can contain the <phrase> element are treated as candidates for word-by-word
       comparison. Note screen, literallayout and programlisting are literals (space preserved) so handled elsewhere. -->
  <xsl:template match="*[not(@xml:space='preserve')]
                        [local-name()='bridgehead' or
                         local-name()='citation' or
                         local-name()='citetitle' or
                         local-name()='classsynopsisinfo' or
                         local-name()='emphasis' or
                         local-name()='entry' or
                         local-name()='firstterm' or
                         local-name()='foreignphrase' or
                         local-name()='funcsynopsisinfo' or
                         local-name()='glosssee' or
                         local-name()='glossseealso' or
                         local-name()='glossterm' or
                         local-name()='button' or
                         local-name()='label' or
                         local-name()='link' or
                         local-name()='member' or
                         local-name()='orgdiv' or
                         local-name()='para' or
                         local-name()='phrase' or
                         local-name()='primary' or
                         local-name()='primaryie' or
                         local-name()='quote' or
                         local-name()='refdescriptor' or
                         local-name()='refentrytitle' or
                         local-name()='refname' or
                         local-name()='refpurpose' or
                         local-name()='secondary' or
                         local-name()='secondaryie' or
                         local-name()='see' or
                         local-name()='seealso' or
                         local-name()='seealsoie' or
                         local-name()='seeie' or
                         local-name()='seg' or
                         local-name()='segtitle' or
                         local-name()='simpara' or
                         local-name()='subtitle' or
                         local-name()='synopsis' or
                         local-name()='td' or
                         local-name()='term' or
                         local-name()='termdef' or
                         local-name()='tertiary' or
                         local-name()='tertiaryie' or
                         local-name()='textobject' or
                         local-name()='th' or
                         local-name()='title' or
                         local-name()='titleabbrev' or
                         local-name()='tocentry']">
    <xsl:copy>
      <xsl:attribute name="deltaxml:word-by-word">true</xsl:attribute>
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates select="node()"/>
    </xsl:copy>
  </xsl:template>


  <!-- Identify any elements where word-by-word processing is not appropriate,
          and line-by-line processing is better -->
  <xsl:template match="*[local-name()='programlisting' or
                         local-name()='blockquote' or
                         local-name()='literallayout' or 
                         local-name()='screen' or
                         local-name()='address' or
                         @xml:space='preserve']">
    <xsl:copy>
      <xsl:attribute name="deltaxml:word-by-word">false</xsl:attribute>
      <xsl:attribute name="xml:space">preserve</xsl:attribute>
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates select="node()" mode="line-by-line"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="*" mode="line-by-line">
    <xsl:copy>
      <xsl:apply-templates select="@*" mode="line-by-line"/>
      <xsl:apply-templates select="node()" mode="line-by-line"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="@*" mode="line-by-line">
    <xsl:copy-of select="."/>
  </xsl:template>

  <!-- This is the XSLT 2.0 version of the following template
     <xsl:template match="text()" mode="line-by-line">
         <xsl:analyze-string select="." flags="m" regex="(^)">
             <xsl:non-matching-substring>
                 <xsl:element name="deltaxml:line" ><xsl:value-of select="."/></xsl:element>
             </xsl:non-matching-substring>
         </xsl:analyze-string>
     </xsl:template> 
     -->
  <xsl:template match="text()" mode="line-by-line">
    <xsl:call-template name="split-string">
      <xsl:with-param name="string-input" select="."/>
    </xsl:call-template>
  </xsl:template>

  <xsl:template name="split-string">
    <xsl:param name="string-input"/>
    <xsl:variable name="new-line" select="'&#x0A;'"/>
    <xsl:choose>
      <xsl:when test="contains($string-input, $new-line)">
        <xsl:variable name="first-line" select="substring-before($string-input, $new-line)"/>
        <xsl:variable name="rest" select="substring-after($string-input, $new-line)"/>
        <xsl:element name="deltaxml:line">
          <xsl:value-of select="concat($first-line, $new-line)"/>
        </xsl:element>
        <xsl:if test="string-length($rest) > 0">
          <xsl:call-template name="split-string">
            <xsl:with-param name="string-input" select="$rest"/>
          </xsl:call-template>
        </xsl:if>
      </xsl:when>
      <xsl:otherwise>
        <xsl:element name="deltaxml:line">
          <xsl:value-of select="$string-input"/>
        </xsl:element>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
   
  <xsl:template match="comment()">
    <xsl:if test="$preserve-comments='true'">
      <xsl:element name="deltaxml:comment">
        <xsl:value-of select="."/>
      </xsl:element>
    </xsl:if>
  </xsl:template>

  <xsl:key name="idmap" match="*/@id" use="."/>

  <!-- For every id attribute, use the value as a key. -->
  <xsl:template match="@id">
    <!-- add a deltaxml:key="XX" attribute, with the same value as the id attribute,
         then copy the original attribute -->
    <xsl:variable name="key-value" select="normalize-space(.)"/>
    <xsl:if test="count(key('idmap', .)) > 1">
      <xsl:message terminate="yes">This document contains non-unique 'id' attributes and cannot be sensibly compared using with DeltaXML DocBook pipeline. 
Please ensure that ids are unique and try again.
Non-unique id: <xsl:value-of select="."/></xsl:message>
    </xsl:if>
    <xsl:attribute name="deltaxml:key">
      <xsl:value-of select="$key-value"/>
    </xsl:attribute>
    <xsl:attribute name="{name()}">
      <xsl:value-of select="$key-value"/>
    </xsl:attribute>
  </xsl:template>

</xsl:stylesheet>
