<!--

# =============================================================================

# Copyright © 2013 Typéfi Systems. All rights reserved.

#

# Unless required by applicable law or agreed to in writing, software

# is distributed on an "as is" basis, without warranties or conditions of any

# kind, either express or implied.

# =============================================================================

-->

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:tps="http://www.typefi.com/ContentXML" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xd="http://www.pnp-software.com/XSLTdoc" version="2.0" exclude-result-prefixes="xs xlink">





    
    <xd:doc type="stylesheet">

        
<xd:short>

            Converts XHTML tables to Cals table

        
</xd:short>

        
<xd:cvsId>   $Revision$</xd:cvsId>

    
</xd:doc>






    
<xsl:template match="table" mode="xhtml-to-cals">

        
<!-- Expand out all the spans -->

        
<xsl:variable name="expanded-spans-table">

            
<xsl:call-template name="expand-spans" />

        
</xsl:variable>



        
<xsl:apply-templates select="$expanded-spans-table" mode="convert-to-cals" />

    
</xsl:template>





    
<xsl:template name="expand-spans">

        
<xsl:apply-templates select="." mode="expand-spans" />

    
</xsl:template>





    
<xsl:template match="table" mode="convert-to-cals">

        
<table>

            
<xsl:apply-templates select="(@border, @width)" mode="convert-to-cals" />

            
<!-- Support <colgroup> -->

            
<tgroup cols="{count(col | colgroup/col)}">

                
<xsl:call-template name="create-table-cals-content" />

            
</tgroup>

        
</table>

    
</xsl:template>





    
<xsl:template match="table/@*" mode="convert-to-cals">

        
<xsl:copy />

    
</xsl:template>





    
<xsl:template name="create-table-cals-content">

        
<xsl:apply-templates mode="convert-to-cals" />

    
</xsl:template>



    
<!-- ===================================================================-->

    
<!-- Create colspec element from cols.  Convert to % based widths as this makes life easier in print -->

    
<!-- ===================================================================-->



    
<xsl:template match="col" mode="convert-to-cals">

        
<xsl:variable name="total-width" select="sum((., parent::colgroup)/../(., colgroup)/col/@width)" as="xs:double" />

        
<xsl:variable name="percentage" select="round(@width div $total-width*100*100) div 100" as="xs:double" />

        
<xsl:variable name="proportional-width" select="concat($percentage, '%')" as="xs:string" />



        
<xsl:call-template name="create-colspec">

            
<xsl:with-param name="colwidth" select="if (tps:is-relative-width(@width)) then @width else $proportional-width" />

        
</xsl:call-template>

    
</xsl:template>



    
<xsl:function name="tps:is-relative-width" as="xs:boolean">

        
<xsl:param name="width" as="attribute(width)" />

        
<xsl:sequence select="matches($width, '[%\*]$')" />

    
</xsl:function>



    
<xsl:template name="create-colspec">

        
<xsl:param name="colwidth" as="xs:string" />

        
<xsl:variable name="col-position">

            
<xsl:number count="col" level="any" from="table" />

        
</xsl:variable>



        
<colspec>

            
<xsl:attribute name="colnum" select="$col-position" />

            
<xsl:attribute name="colname" select="concat('col', $col-position)" />

            
<xsl:attribute name="colwidth" select="$colwidth" />

        
</colspec>

    
</xsl:template>



    
<!-- ===================================================================-->

    
<!-- Do a 1-to-1 transform of all the matching elements                                                        -->

    
<!-- ===================================================================-->



    
<xsl:template match="thead" mode="convert-to-cals">

        
<thead>

            
<xsl:apply-templates mode="convert-to-cals" />

        
</thead>

    
</xsl:template>



    
<xsl:template match="tbody" mode="convert-to-cals">

        
<tbody>

            
<xsl:apply-templates mode="convert-to-cals" />

        
</tbody>

    
</xsl:template>



    
<xsl:template match="tfoot" mode="convert-to-cals">

        
<tfoot>

            
<xsl:apply-templates mode="convert-to-cals" />

        
</tfoot>

    
</xsl:template>



    
<xsl:template match="tr" mode="convert-to-cals">

        
<row>

            
<xsl:apply-templates mode="convert-to-cals" />

        
</row>

    
</xsl:template>



    
<!-- ===================================================================-->

    
<!-- processes the cells.  Convert across all the attributes and copy the contents  -->

    
<!-- ===================================================================-->



    
<xsl:template match="th[@style] | td[@style]" mode="convert-to-cals">

        
<xsl:processing-instruction name="style" select="@style" />

        
<xsl:next-match />

    
</xsl:template>



    
<xsl:template match="td | th" mode="convert-to-cals">

        
<xsl:variable name="preceding-cells-count" select="count(preceding-sibling::*)" />



        
<entry>

            
<xsl:apply-templates select="@valign | @align | @rowspan | @char" mode="convert-to-cals" />



            
<xsl:attribute name="namest" select="$preceding-cells-count + 1" />



            
<xsl:attribute name="nameend" select="$preceding-cells-count + (@xcolspan, 1)[1]" />



            
<xsl:apply-templates select="." mode="pre-processing" />

        
</entry>

    
</xsl:template>



    
<xsl:template match="tr/processing-instruction()" mode="convert-to-cals">

        
<xsl:copy-of select="." />

    
</xsl:template>



    
<xsl:template match="@valign | @align | @char" mode="convert-to-cals">

        
<xsl:copy-of select="." />

    
</xsl:template>



    
<xsl:template match="@rowspan" mode="convert-to-cals">

        
<xsl:attribute name="morerows" select="number(.) - 1" />

    
</xsl:template>



    
<!-- ===================================================================-->

    
<!-- Drop the padding cells                                                                 -->

    
<!-- ===================================================================-->



    
<xsl:template match="td[(@spanCellCol, @spanCellRow) = 'yes']" mode="convert-to-cals" priority="10" />

    
<xsl:template match="th[(@spanCellCol, @spanCellRow) = 'yes']" mode="convert-to-cals" priority="10" />



    
<!-- ===================================================================-->

    
<!-- Per default all existing nodes should be copied into the result document                                 -->

    
<!-- ===================================================================-->



    
<xsl:template match="node() | @*" mode="expand-spans">

        
<xsl:copy copy-namespaces="no">

            
<xsl:apply-templates select="@* | node()" mode="#current" />

        
</xsl:copy>

    
</xsl:template>



    
<!-- ===================================================================-->

    
<!-- thead, tbody and tfoot has their tr elements padded out with dummy cells                                 -->

    
<!-- ===================================================================-->



    
<xsl:template match="thead|tbody|tfoot" mode="expand-spans">

        
<xsl:element name="{local-name(.)}" inherit-namespaces="no">

            
<xsl:copy-of select="@*" copy-namespaces="no" />

            
<xsl:call-template name="process-block">

                
<xsl:with-param name="source-rows" select="self::*" />

                
<xsl:with-param name="col-count" select="count(../col)" tunnel="yes" />

            
</xsl:call-template>

        
</xsl:element>

    
</xsl:template>



    
<!-- ===================================================================-->

    
<!-- Expand out the spans in a blocks of tr nodes -->

    
<!-- ===================================================================-->

    
<xsl:template name="process-block">

        
<!-- Source tr elements pre-padding -->

        
<xsl:param name="source-rows" as="element()+" />

        
<!-- Altered tr elements after padding -->

        
<xsl:param name="processed-row" as="document-node()*" />

        
<!-- row being padded-->

        
<xsl:param name="row-count" as="xs:integer">1</xsl:param>

        
<xsl:param name="col-count" as="xs:integer?" tunnel="yes" />



        
<xsl:choose>

            
<xsl:when test="count($source-rows/tr) &lt; $row-count">

                
<!-- stop padding when all the rows are done -->

            
</xsl:when>

            
<xsl:when test="count($processed-row/node())=0">

                
<!-- First row is different as it will have no preceding rowspans -->

                
<xsl:variable name="expanded" as="element()">

                    
<xsl:element name="tr" inherit-namespaces="no">

                        
<xsl:copy-of select="tps:expand-col-spans($source-rows/tr[1])" />

                    
</xsl:element>

                
</xsl:variable>



                
<xsl:variable name="first-row" as="document-node()">

                    
<xsl:copy-of select="tps:create-supplementary-cells($expanded, $col-count)" />

                
</xsl:variable>



                
<xsl:copy-of select="$first-row" />

                
<xsl:call-template name="process-block">

                    
<xsl:with-param name="source-rows" select="$source-rows" />

                    
<xsl:with-param name="processed-row" select="$first-row" />

                    
<xsl:with-param name="row-count">2</xsl:with-param>

                
</xsl:call-template>

            
</xsl:when>

            
<xsl:otherwise>

                
<!-- process the rest -->

                
<xsl:variable name="row">

                    
<xsl:copy-of select="tps:expand-table-row($source-rows, $processed-row, $row-count, $col-count)" />

                
</xsl:variable>

                
<xsl:copy-of select="$row" />

                
<xsl:call-template name="process-block">

                    
<xsl:with-param name="source-rows" select="$source-rows" />

                    
<xsl:with-param name="processed-row" select="$row" />

                    
<xsl:with-param name="row-count" select="$row-count+1" />

                
</xsl:call-template>

            
</xsl:otherwise>

        
</xsl:choose>

    
</xsl:template>





    
<!-- ===================================================================-->

    
<!-- Expand out the spans in sinlge tr node                                                                         -->

    
<!--  This is done by first expanding the rowspans down and then expanding the colspans accross        -->

    
<!-- ===================================================================-->





    
<xsl:function name="tps:expand-table-row" as="item()+">

        
<!-- block of Source tr nodes -->

        
<xsl:param name="table-block" as="element()+" />

        
<!-- row being created that has preexpanded content -->

        
<xsl:param name="expanding-row" as="document-node()+" />

        
<!-- row being expanded -->

        
<xsl:param name="row" as="xs:integer" />

        
<xsl:param name="col-count" as="xs:integer?" />



        
<!-- expand the row spans first -->

        
<xsl:variable name="expanded" as="element()">

            
<xsl:element name="tr" inherit-namespaces="no">

                
<xsl:variable name="current-row" select="$table-block/tr[$row]" as="element()" />



                
<xsl:copy-of select="tps:expand-row-spans($current-row, $expanding-row/node())" />

            
</xsl:element>

        
</xsl:variable>



        
<xsl:variable name="next-row" select="tps:create-supplementary-cells($expanded, $col-count)" as="document-node()" />



        
<!-- use the row with expanded rowspans and expand out the colspans-->

        
<xsl:variable name="next-row-expanded">

            
<xsl:element name="tr" inherit-namespaces="no">

                
<xsl:copy-of select="tps:expand-col-spans($next-row/node())" />

            
</xsl:element>

        
</xsl:variable>

        
<xsl:copy-of select="$next-row-expanded" />

    
</xsl:function>



    
<!-- ===================================================================-->

    
<!-- Expand out the colspans in sinlge tr node                                                                 -->

    
<!--  This is done by adding extra cells to fully padout the row.  Inserted cells have a special attrib         -->

    
<!-- ===================================================================-->



    
<xsl:function name="tps:expand-col-spans" as="item()+">

        
<!-- row will have colspans expanded -->

        
<xsl:param name="source-row" as="element()+" />



        
<xsl:variable name="expand-columns">

            
<xsl:for-each select="$source-row/*">

                
<xsl:variable name="element-name" select="local-name()" />

                
<xsl:variable name="current-cell" select="self::node()" />



                
<xsl:element name="{$element-name}" inherit-namespaces="no">

                    
<xsl:copy-of select="$current-cell/@*[not(name()='colspan')]" copy-namespaces="no" />



                    
<xsl:variable name="colspan" select="$current-cell/@colspan" />

                    
<xsl:if test="$colspan">

                        
<xsl:attribute name="xcolspan" select="$colspan" />

                    
</xsl:if>



                    
<xsl:copy-of select="$current-cell/child::node()" copy-namespaces="no" />

                
</xsl:element>



                
<!-- If there is a colspan add padding cells  -->

                
<xsl:for-each select="2 to (xs:integer(@colspan))">

                    
<xsl:element name="{$element-name}" inherit-namespaces="no">

                        
<xsl:attribute name="spanCellCol">yes</xsl:attribute>

                        
<xsl:copy-of select="$current-cell/@*[not(name()='colspan')]" copy-namespaces="no" />

                        
<xsl:comment>

                            
<xsl:copy-of select="$current-cell/child::node()" copy-namespaces="no" />

                        
</xsl:comment>

                    
</xsl:element>

                
</xsl:for-each>

            
</xsl:for-each>

        
</xsl:variable>



        
<xsl:copy-of select="$source-row/processing-instruction()" />

        
<xsl:copy-of select="$expand-columns" />

    
</xsl:function>



    
<!-- ===================================================================-->

    
<!-- Expand out the rowspans in single tr node to the next tr node                                                -->

    
<!-- This is done by adding extra cells to fully padout the row below or copying cells across.         -->

    
<!-- ===================================================================-->





    
<xsl:function name="tps:expand-row-spans" as="item()+">

        
<xsl:param name="source-rows" as="element()+" />

        
<!-- source table rows to copy from -->

        
<xsl:param name="modified-row" as="element()+" />

        
<!-- new row being created when expanding the rowspans -->



        
<xsl:for-each select="$modified-row/*">

            
<xsl:choose>

                
<!-- if the rowspan of the cell aobve is greater than 1 create a padding cell.  Decrement the rowspan for the dummy cell -->

                
<xsl:when test="@rowspan &gt; 1">

                    
<xsl:element name="{local-name()}">

                        
<xsl:attribute name="spanCellRow">yes</xsl:attribute>

                        
<xsl:copy-of select="@*[not(name()='rowspan')]" copy-namespaces="no" />

                        
<xsl:attribute name="rowspan" select="number(@rowspan)-1" />

                        
<xsl:comment>

                            
<xsl:copy-of select="child::node()" />

                        
</xsl:comment>

                    
</xsl:element>

                
</xsl:when>

                
<!-- if there are no spans just copy from the original cell -->

                
<xsl:otherwise>

                    
<xsl:variable name="current-column" select="count(preceding-sibling::*)+1" />

                    
<xsl:variable name="spanned-row-cells" select="count(preceding-sibling::*[@rowspan &gt; 1])" />



                    
<xsl:copy-of select="$source-rows/processing-instruction()" />

                    
<xsl:copy-of select="tps:select-cell($current-column - $spanned-row-cells,$source-rows,1,0)" copy-namespaces="no" />

                
</xsl:otherwise>

            
</xsl:choose>

        
</xsl:for-each>

    
</xsl:function>





    
<xsl:function name="tps:create-supplementary-cells" as="document-node()">

        
<xsl:param name="row" as="element()" />

        
<xsl:param name="col-count" as="xs:integer?" />



        
<xsl:document>

            
<xsl:for-each select="$row">

                
<xsl:copy>

                    
<xsl:copy-of select="@*, processing-instruction(), *" />



                    
<xsl:for-each select="sum(for $c in * return (xs:integer($c/@colspan), 1)[1]) + 1 to $col-count">

                        
<td spanCellCol="supplemented" />

                    
</xsl:for-each>

                
</xsl:copy>

            
</xsl:for-each>

        
</xsl:document>

    
</xsl:function>





    
<xsl:function name="tps:select-cell">

        
<!-- Current Column Being Processed  -->

        
<xsl:param name="src-column-no" as="xs:integer" />

        
<!-- Current table show being processed -->

        
<xsl:param name="row" as="element()+" />

        
<!-- Current column being examised to copy -->

        
<xsl:param name="current-column-count" as="xs:integer" />

        
<!-- Total of the spans already checked -->

        
<xsl:param name="current-span-col-total" as="xs:double" />



        
<!-- colspan of the current cell being examined-->



        
<xsl:variable name="current-span">

            
<xsl:choose>

                
<xsl:when test="$row/*[$current-column-count]/@colspan">

                    
<xsl:value-of select="$row/*[$current-column-count]/@colspan" />

                
</xsl:when>

                
<xsl:otherwise>1</xsl:otherwise>

            
</xsl:choose>

        
</xsl:variable>



        
<xsl:choose>

            
<!-- Current column being processed matches the end of the span. i.e. span finishes here.  Output cell -->

            
<xsl:when test="$src-column-no=$current-span-col-total+$current-span">

                
<xsl:copy-of select="$row/*[$current-column-count]" copy-namespaces="no" />

            
</xsl:when>

            
<!-- The span total exceeds the current colum.   This means the current cell is not a span boundry & we have gone past -->

            
<xsl:when test="$src-column-no &lt; $current-span-col-total+$current-span">

                
<!-- do nothing and exit the recurssion -->

            
</xsl:when>

            
<!-- The span total is less than the current colum. This means the current cell is not a span boundry. Try the next cell  -->

            
<xsl:when test="$src-column-no &gt; $current-span-col-total+$current-span">

                
<xsl:copy-of select="tps:select-cell($src-column-no,$row,$current-column-count+1, $current-span+ $current-span-col-total)" copy-namespaces="no" />

            
</xsl:when>

            
<xsl:otherwise>

                
<xsl:message terminate="no">Error in table conversion. Please contact Typéfi Support</xsl:message>

            
</xsl:otherwise>

        
</xsl:choose>

    
</xsl:function>

</xsl:stylesheet>













































































v