Subject: AW: [xsl] Stylesheet for converting XHTML tables to CALS From: "Huditsch, Roman \(LNG-VIE\)" <Roman.Huditsch@xxxxxxxxxxxxx> Date: Wed, 8 Mar 2006 14:54:48 +0100 |
Hi again, I tried to come up with a solution for the colspan and rowspan problem when doing a HTML to CALS table transformation. All I could think of was a three pass transformation. 1. create additional table cells for each colspan attribute (number according to the colspan value) 2. create additional table cells for each rowspan attribute in a preceding row 3. do the transformation an delete previously created cells Here comes the stylesheet: <?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE xsl:stylesheet [ <!ENTITY preceding_rowspan_td "preceding::xhtml:td[count(preceding-sibling::xhtml:td)=current()/count(prece ding-sibling::xhtml:td)+1 and @rowspan]"> ]> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ln="http://www.lexisnexis.at/xhtml-cals" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsldoc="http://www.bacman.net/XSLdoc" xmlns:xhtml="http://www.w3.org/1999/xhtml" exclude-result-prefixes="xsldoc xs ln xhtml" xmlns:doc="http://docbook.org/ns/docbook"> <!-- =================================================================== --> <!-- --> <!-- This Stylesheets converts arbitrary XHTML tables into tables conforming to the --> <!-- OASIS CALS model --> <!-- --> <!-- --> <!-- Author: Roman Huditsch, roman.huditsch@xxxxxxxxxxxxx --> <!-- --> <!-- =================================================================== --> <xsl:output method="xhtml" version="1.0" encoding="ISO-8859-1"/> <xsldoc:author>Roman Huditsch</xsldoc:author> <xsldoc:date>March 2, 2006</xsldoc:date> <xsldoc:version>Version 0.9</xsldoc:version> <xsl:namespace-alias stylesheet-prefix="" result-prefix="xhtml"/> <!-- =================================================================== --> <!-- Per default all existing nodes should be copied into the result document --> <!-- =================================================================== --> <xsl:template match="node() | @*" mode="process first-pass second-pass"> <xsl:copy> <xsl:apply-templates select="@* | node()" mode="#current"/> </xsl:copy> </xsl:template> <!-- =================================================================== --> <!-- HTML --> <!-- =================================================================== --> <xsl:template match="xhtml:html"> <!-- =================================================================== --> <!-- First Pass - Create a variable with "expanded" table cells based on @colspan --> <!-- =================================================================== --> <xsl:variable name="first-pass" as="element()+"> <xsl:copy> <xsl:copy-of select="@*"/> <xsl:apply-templates mode="first-pass"/> </xsl:copy> </xsl:variable> <!--xsl:message select="$first-pass"/--> <!-- =================================================================== --> <!-- Second Pass - Create a variable with "expanded" table cells based on @rowspan --> <!-- =================================================================== --> <xsl:variable name="second-pass" as="element()+"> <xsl:copy> <xsl:copy-of select="@*"/> <xsl:apply-templates select="$first-pass/*" mode="second-pass"/> </xsl:copy> </xsl:variable> <xsl:copy> <xsl:namespace name="doc" select="'http://docbook.org/ns/docbook'"/> <xsl:namespace name="xhtml" select="'http://www.w3.org/1999/xhtml'"/> <xsl:apply-templates select="$second-pass" mode="process"/> </xsl:copy> </xsl:template> <!-- =================================================================== --> <!-- Table --> <!-- =================================================================== --> <xsl:template match="xhtml:table" mode="process"> <!-- Create param to indicate border handling to child nodes --> <xsl:param name="border" select="not(starts-with(@border,'0'))" tunnel="yes"/> <!-- =================================================================== --> <!-- Continue with processing --> <!-- =================================================================== --> <doc:table> <xsl:apply-templates select="(@border, @width)" mode="process"/> <!-- <tgroup> --> <doc:tgroup> <xsl:message select="concat('Max Columns: ', ln:max_columns(.))"/> <xsl:call-template name="generate-colspecs"> <xsl:with-param name="max" select="ln:max_columns(.)" as="xs:double"/> </xsl:call-template> </doc:tgroup> <!-- <thead> --> <xsl:apply-templates select="xhtml:thead" mode="process"/> <!-- <tbody> --> <doc:tbody> <xsl:apply-templates select="xhtml:tr | xhtml:tbody/xhtml:tr" mode="process"/> </doc:tbody> <!-- <tfoot> --> <xsl:apply-templates select="xhtml:tfoot" mode="process"/> </doc:table> </xsl:template> <!-- =================================================================== --> <!-- Table attributes --> <!-- =================================================================== --> <xsl:template match="@border" mode="process"> <xsl:attribute name="frame"> <xsl:value-of select="if(starts-with(., '0')) then('none') else('all')"/> </xsl:attribute> </xsl:template> <xsl:template match="xhtml:table/@width" mode="process"> <xsl:attribute name="pgwide"> <xsl:value-of select="if(.='100%') then('0') else('1')"/> </xsl:attribute> </xsl:template> <!-- =================================================================== --> <!-- colspec --> <!-- =================================================================== --> <xsl:template name="generate-colspecs"> <xsl:param name="border" tunnel="yes"/> <xsl:param name="max" as="xs:double"/> <xsl:param name="count" select="1" as="xs:double"/> <xsl:choose> <xsl:when test="$count > $max"/> <xsl:otherwise> <doc:colspec colnum="{$count}" colname="{concat('col', $count)}" colsep="{if($border) then('1') else('0')}"> <xsl:choose> <xsl:when test="xhtml:colgroup/xhtml:col[$count]/@width"> <xsl:apply-templates select="xhtml:colgroup/xhtml:col[$count]/@width" mode="process"/> </xsl:when> <xsl:when test="( ./(*/* | *)/xhtml:td[$count] | ./(*/* | *)/xhtml:th[$count])/@width"> <xsl:attribute name="colwidth"> <xsl:value-of select="concat(ln:max_width(., $count), '*')"/> </xsl:attribute> </xsl:when> </xsl:choose> </doc:colspec> <xsl:call-template name="generate-colspecs"> <xsl:with-param name="max" select="$max"/> <xsl:with-param name="count" select="$count + 1"/> </xsl:call-template> </xsl:otherwise> </xsl:choose> </xsl:template> <!-- =================================================================== --> <!-- thead, tfoot --> <!-- =================================================================== --> <xsl:template match="xhtml:thead | xhtml:tfoot" mode="process"> <xsl:element name="{local-name()}" namespace="http://docbook.org/ns/docbook"> <xsl:copy-of select="@valign"/> <xsl:apply-templates mode="process"/> </xsl:element> </xsl:template> <!-- =================================================================== --> <!-- TR --> <!-- =================================================================== --> <xsl:template match="xhtml:tr" mode="process"> <xsl:param name="border" tunnel="yes"/> <doc:row rowsep="{if($border) then('1') else('0')}"> <xsl:copy-of select="@valign"/> <xsl:apply-templates mode="process"/> </doc:row> </xsl:template> <!-- =================================================================== --> <!-- TD --> <!-- =================================================================== --> <xsl:template match="xhtml:td" mode="process"> <xsl:variable name="position" select="count(preceding-sibling::*) + 1"/> <doc:entry colname="col{$position}"> <xsl:if test="@colspan > 1"> <xsl:attribute name="namest"> <xsl:value-of select="concat('col',$position)"/> </xsl:attribute> <xsl:attribute name="nameend"> <xsl:value-of select="concat('col',$position + number(@colspan) - 1)"/> </xsl:attribute> </xsl:if> <xsl:if test="@rowspan > 1"> <xsl:attribute name="morerows"> <xsl:value-of select="number(@rowspan) - 1"/> </xsl:attribute> </xsl:if> <xsl:copy-of select="@align"/> <xsl:apply-templates mode="process"/> </doc:entry> </xsl:template> <!-- ======================================================================= --> <!-- Function for counting the number of columns - Input: Context Element, Output: Maximum Double --> <!-- ======================================================================= --> <xsl:function name="ln:max_columns" as="xs:double"> <xsl:param name="context" as="element()"/> <xsl:choose> <xsl:when test="$context/xhtml:colgroup[not(@span)]"> <xsl:sequence select="count($context/xhtml:colgroup/xhtml:col)"/> </xsl:when> <xsl:when test="$context/xhtml:colgroup[@span]"> <xsl:sequence select="$context/xhtml:colgroup/@span"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="max(for $x in ($context | $context/* )/xhtml:tr return count($x/xhtml:td))"/> </xsl:otherwise> </xsl:choose> </xsl:function> <!-- ============================================================================== --> <!-- Function for searching the maximun width for a column - Input: Context Element, Output: Maximum Double --> <!-- ============================================================================== --> <xsl:function name="ln:max_width" as="xs:double"> <xsl:param name="context" as="element()"/> <xsl:param name="count" as="xs:double"/> <xsl:sequence select="max(for $x in ($context/* | $context/*/* )/(xhtml:td[$count] | xhtml:th[$count])/@width return (if($x castable as xs:double) then($x) else(replace($x, '[a-z%]', ''))))"/> </xsl:function> <!-- =================================================================== --> <!-- Suppressed elements --> <!-- =================================================================== --> <xsl:template match="xhtml:colgroup | xhtml:td[@id=('rowspan', 'colspan')]" mode="process"/> <!-- =================================================================== --> <!-- First Pass - create empty cells for colspans --> <!-- =================================================================== --> <xsl:template match="xhtml:*[@colspan]" mode="first-pass"> <xhtml:td> <xsl:copy-of select="@*"/> <xsl:apply-templates mode="first-pass"/> </xhtml:td> <xsl:for-each select="1 to (xs:integer(@colspan)-1)"> <xhtml:td id="colspan"/> </xsl:for-each> </xsl:template> <!-- =================================================================== --> <!-- Second Pass - create empty cells for rowspans --> <!-- =================================================================== --> <xsl:template match="xhtml:td[&preceding_rowspan_td;]" mode="second-pass"> <xsl:variable name="rowDiff" select="parent::xhtml:tr/count(preceding-sibling::*)+1 - (&preceding_rowspan_td;[1]/parent::xhtml:tr/count(preceding-sibling::*)+1)" as="xs:integer"/> <xsl:variable name="rowspan" select="&preceding_rowspan_td;[1]/@rowspan" as="xs:integer"/> <xsl:copy> <xsl:copy-of select="@*"/> <xsl:apply-templates mode="second-pass"/> </xsl:copy> <xsl:if test="$rowDiff < $rowspan"> <xsl:for-each select="1 to ($rowspan - 1)"> <td id="rowspan"/> </xsl:for-each> </xsl:if> </xsl:template> </xsl:stylesheet> Every feedback is welcome! wbr, Roman > -----Urspr|ngliche Nachricht----- > Von: David Carlisle [mailto:davidc@xxxxxxxxx] > Gesendet: Montag, 06. Mdrz 2006 13:03 > An: xsl-list@xxxxxxxxxxxxxxxxxxxxxx > Betreff: Re: [xsl] Stylesheet for converting XHTML tables to CALS > > > > I just finished my first attempt to transform XHTML tables > into tables > > conforming to the CALS table model. > > Attached is my XSLT 2.0 stylesheet. Every feedback is > heartily welcome > > :) > > You appear to be generating elements in the xhtml namespace > they should probably be in no-namespace or the new docbook 5 > namespace or something, seeing as <entry> etc are not xhtml. > > <xsl:param name="border" select="if(starts-with(@border, > '0')) then(xs:boolean(0)) else(xs:boolean(1))" as="xs:boolean" > tunnel="yes"/> > > you are starting with a boolean value > starts-with(@border,'0') > then if it is true, taking an integer literal and coercing it > to a boolean. If you need boolean values you can just use > true() and false() but here you just need <xsl:param > name="border" select="not(starts-with(@border,'0'))"/> > > > <xsl:apply-templates > select="xhtml:tr[not(parent::*[local-name()=('thead', > 'tbody', 'tfoot')])] | xhtml:tbody/xhtml:tr"/> > > It's best not to use local-name() in such tests but just to > use name tests (which are namespace aware) however in this > case the current element is <table> so the parent of every > element selected by xhtml:tr is table and so the filter > testing on local-name is not doing anything. > so it could be > > select="xhtml:tr| xhtml:tbody/xhtml:tr"/> > > > In > > <xsl:template match="xhtml:th | xhtml:td"> > <xsl:variable name="position" > select="count(preceding-sibling::*) + 1"/> > <entry> > <xsl:if test="@colspan > 1"> > <xsl:attribute name="namest"> > <xsl:value-of > select="concat('col',$position)"/> > > don't you need to take account of any colspan attributes in > earlier columns, and rowspan attributes in earlier rows in > order to know which coulmn an entry in a table corresponds > to? (This is the hardest part of switching between html and > cals tables). In the above you are assuming that the second > td entry in a row is corresponding to the second column, but > this is not the case if the first entry spans columns, or if > an entry in an earlier row spans into the first cell of this row. > > David > > ______________________________________________________________ > __________ > This e-mail has been scanned for all viruses by Star. The > service is powered by MessageLabs. For more information on a > proactive anti-virus service working around the clock, around > the globe, visit: > http://www.star.net.uk > ______________________________________________________________ > __________
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
AW: [xsl] Stylesheet for converting, Huditsch, Roman \(LN | Thread | [xsl] XSL with CSS, koteshwar.venigalla |
Re: [xsl] when to use 'as' attribut, tom tom | Date | Re: [xsl] when to use 'as' attribut, David Carlisle |
Month |