Re: [xsl] XSL to ODF/OOXML

Subject: Re: [xsl] XSL to ODF/OOXML
From: Steve <subsume@xxxxxxxxx>
Date: Fri, 27 Apr 2007 15:13:24 -0400
Interestingly, I was consindering emailing you after stumbling upon this:

http://www.biglist.com/lists/xsl-list/archives/200703/msg00360.html

On 4/27/07, Nic James Ferrier <nferrier@xxxxxxxxxxxxxxxxxxxx> wrote:
"Joe Fawcett" <joefawcett@xxxxxxxxxxx> writes:

>> I'm scouring the internet looking for leads on creating ODF/OOXML with
>> XSL transforms. I'm not really finding a whole lot, other than command
>> line programs which accomplish as much.
>>
>> I have a website with lots of reports and, ideally, I'd like to have
>> an 'export to Word' feature. Is this just another XSL transform that
>> requires me learning the appropriate output schema or is there
>> something additional that needs to be done?
>>
>> Also, I already have HTML versions of the reports I need (nothing too
>> complicated). I'm wondering if I can use the XHTML output as my source
>> XML and have one stylesheet that converts all of my documents into the
>> appropriate format? Or am I reaching for the philosopher's stone too
>> soon?

I have an XSLT to convert HTML to ODF.

Here it is:

  <?xml version="1.0" encoding="utf-8"?>
  <xsl:stylesheet  version="1.0"
                   xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
                   xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
                   xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
                   xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
                   xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
                   xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
                   xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"
                   xmlns:xlink="http://www.w3.org/1999/xlink";
                   xmlns:dc="http://purl.org/dc/elements/1.1/";
                   xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0"
                   xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0"
                   xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"
                   xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
                   xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0"
                   xmlns:math="http://www.w3.org/1998/Math/MathML";
                   xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0"
                   xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0"
                   xmlns:ooo="http://openoffice.org/2004/office";
                   xmlns:ooow="http://openoffice.org/2004/writer";
                   xmlns:oooc="http://openoffice.org/2004/calc";
                   xmlns:dom="http://www.w3.org/2001/xml-events";
                   xmlns:xforms="http://www.w3.org/2002/xforms";
                   xmlns:xsd="http://www.w3.org/2001/XMLSchema";
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";>

      <!--
           Copyright (C) 2006 by Tapsell-Ferrier Limited

           This program is free software; you can redistribute it and/or modify
           it under the terms of the GNU General Public License as published by
           the Free Software Foundation; either version 2, or (at your option)
           any later version.

           This program is distributed in the hope that it will be useful,
           but WITHOUT ANY WARRANTY; without even the implied warranty of
           MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
           GNU General Public License for more details.

           You should have received a copy of the GNU General Public License
           along with this program; see the file COPYING.  If not, write to the
           Free Software Foundation, Inc.,   51 Franklin Street, Fifth Floor,
           Boston, MA  02110-1301  USA
        -->

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

      <xsl:template match="/html">
          <office:document-content office:version="1.0">
              <office:scripts/>
              <office:font-face-decls>
                  <style:font-face style:name="StarSymbol" svg:font-family="StarSymbol" style:font-charset="x-symbol"/>
                  <style:font-face style:name="DejaVu Sans1" svg:font-family="'DejaVu Sans'" style:font-pitch="variable"/>
                  <style:font-face style:name="DejaVu Serif" svg:font-family="'DejaVu Serif'" style:font-family-generic="roman" style:font-pitch="variable"/>
                  <style:font-face style:name="DejaVu Sans" svg:font-family="'DejaVu Sans'" style:font-family-generic="swiss" style:font-pitch="variable"/>
              </office:font-face-decls>
              <office:automatic-styles>
                  <style:style style:name="Table1" style:family="table">
                      <style:table-properties style:width="6.925in" table:align="margins"/>
                  </style:style>
                  <style:style style:name="Table1.A" style:family="table-column">
                      <style:table-column-properties style:column-width="3.4625in" style:rel-column-width="32767*"/>
                  </style:style>
                  <style:style style:name="Table1.A1" style:family="table-cell">
                      <style:table-cell-properties fo:padding="0.0382in" fo:border-left="0.0007in solid #000000" fo:border-right="none" fo:border-top="0.0007in solid #000000" fo:border-bottom="0.0007in solid #000000"/>
                  </style:style>
                  <style:style style:name="Table1.B1" style:family="table-cell">
                      <style:table-cell-properties fo:padding="0.0382in" fo:border="0.0007in solid #000000"/>
                  </style:style>
                  <style:style style:name="Table1.A2" style:family="table-cell">
                      <style:table-cell-properties fo:padding="0.0382in" fo:border-left="0.0007in solid #000000" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.0007in solid #000000"/>
                  </style:style>
                  <style:style style:name="Table1.B2" style:family="table-cell">
                      <style:table-cell-properties fo:padding="0.0382in" fo:border-left="0.0007in solid #000000" fo:border-right="0.0007in solid #000000" fo:border-top="none" fo:border-bottom="0.0007in solid #000000"/>
                  </style:style>
                  <style:style style:name="Table2" style:family="table">
                      <style:table-properties style:width="6.925in" table:align="margins"/>
                  </style:style>
                  <style:style style:name="Table2.A" style:family="table-column">
                      <style:table-column-properties style:column-width="3.4625in" style:rel-column-width="32767*"/>
                  </style:style>
                  <style:style style:name="Table2.A1" style:family="table-cell">
                      <style:table-cell-properties fo:padding="0.0382in" fo:border-left="0.0007in solid #000000" fo:border-right="none" fo:border-top="0.0007in solid #000000" fo:border-bottom="0.0007in solid #000000"/>
                  </style:style>
                  <style:style style:name="Table2.B1" style:family="table-cell">
                      <style:table-cell-properties fo:padding="0.0382in" fo:border="0.0007in solid #000000"/>
                  </style:style>
                  <style:style style:name="Table2.A2" style:family="table-cell">
                      <style:table-cell-properties fo:padding="0.0382in" fo:border-left="0.0007in solid #000000" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.0007in solid #000000"/>
                  </style:style>
                  <style:style style:name="Table2.B2" style:family="table-cell">
                      <style:table-cell-properties fo:padding="0.0382in" fo:border-left="0.0007in solid #000000" fo:border-right="0.0007in solid #000000" fo:border-top="none" fo:border-bottom="0.0007in solid #000000"/>
                  </style:style>
                  <style:style style:name="P1" style:family="paragraph" style:parent-style-name="Table_20_Heading">
                      <style:paragraph-properties fo:text-align="start" style:justify-single-word="false"/>
                      <style:text-properties fo:font-style="normal" fo:font-weight="normal" style:font-style-asian="normal" style:font-weight-asian="normal" style:font-style-complex="normal" style:font-weight-complex="normal"/>
                  </style:style>
                  <style:style style:name="P2" style:family="paragraph" style:parent-style-name="Standard" style:list-style-name="L1"/>
                  <style:style style:name="P3" style:family="paragraph" style:parent-style-name="Standard" style:list-style-name="L2"/>
                  <text:list-style style:name="L1">
                      <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="&#x25CF;">
                          <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in"/>
                          <style:text-properties style:font-name="StarSymbol"/>
                      </text:list-level-style-bullet>
                      <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="&#x25CB;">
                          <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in"/>
                          <style:text-properties style:font-name="StarSymbol"/>
                      </text:list-level-style-bullet>
                      <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="&#x25A0;">
                          <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in"/>
                          <style:text-properties style:font-name="StarSymbol"/>
                      </text:list-level-style-bullet>
                      <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="&#x25CF;">
                          <style:list-level-properties text:space-before="1in" text:min-label-width="0.25in"/>
                          <style:text-properties style:font-name="StarSymbol"/>
                      </text:list-level-style-bullet>
                      <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="&#x25CB;">
                          <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in"/>
                          <style:text-properties style:font-name="StarSymbol"/>
                      </text:list-level-style-bullet>
                      <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="&#x25A0;">
                          <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in"/>
                          <style:text-properties style:font-name="StarSymbol"/>
                      </text:list-level-style-bullet>
                      <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="&#x25CF;">
                          <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in"/>
                          <style:text-properties style:font-name="StarSymbol"/>
                      </text:list-level-style-bullet>
                      <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="&#x25CB;">
                          <style:list-level-properties text:space-before="2in" text:min-label-width="0.25in"/>
                          <style:text-properties style:font-name="StarSymbol"/>
                      </text:list-level-style-bullet>
                      <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="&#x25A0;">
                          <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in"/>
                          <style:text-properties style:font-name="StarSymbol"/>
                      </text:list-level-style-bullet>
                      <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="&#x25CF;">
                          <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in"/>
                          <style:text-properties style:font-name="StarSymbol"/>
                      </text:list-level-style-bullet>
                  </text:list-style>
                  <text:list-style style:name="L2">
                      <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="&#x25CF;">
                          <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in"/>
                          <style:text-properties style:font-name="StarSymbol"/>
                      </text:list-level-style-bullet>
                      <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="&#x25CB;">
                          <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in"/>
                          <style:text-properties style:font-name="StarSymbol"/>
                      </text:list-level-style-bullet>
                      <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="&#x25A0;">
                          <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in"/>
                          <style:text-properties style:font-name="StarSymbol"/>
                      </text:list-level-style-bullet>
                      <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="&#x25CF;">
                          <style:list-level-properties text:space-before="1in" text:min-label-width="0.25in"/>
                          <style:text-properties style:font-name="StarSymbol"/>
                      </text:list-level-style-bullet>
                      <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="&#x25CB;">
                          <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in"/>
                          <style:text-properties style:font-name="StarSymbol"/>
                      </text:list-level-style-bullet>
                      <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="&#x25A0;">
                          <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in"/>
                          <style:text-properties style:font-name="StarSymbol"/>
                      </text:list-level-style-bullet>
                      <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="&#x25CF;">
                          <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in"/>
                          <style:text-properties style:font-name="StarSymbol"/>
                      </text:list-level-style-bullet>
                      <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="&#x25CB;">
                          <style:list-level-properties text:space-before="2in" text:min-label-width="0.25in"/>
                          <style:text-properties style:font-name="StarSymbol"/>
                      </text:list-level-style-bullet>
                      <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="&#x25A0;">
                          <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in"/>
                          <style:text-properties style:font-name="StarSymbol"/>
                      </text:list-level-style-bullet>
                      <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="&#x25CF;">
                          <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in"/>
                          <style:text-properties style:font-name="StarSymbol"/>
                      </text:list-level-style-bullet>
                  </text:list-style>
              </office:automatic-styles>
              <xsl:apply-templates select="body"/>
          </office:document-content>
      </xsl:template>

      <xsl:template match="body">
          <office:body>
              <office:text>
                  <office:forms form:automatic-focus="false" form:apply-design-mode="false"/>
                  <text:sequence-decls>
                      <text:sequence-decl text:display-outline-level="0" text:name="Illustration"/>
                      <text:sequence-decl text:display-outline-level="0" text:name="Table"/>
                      <text:sequence-decl text:display-outline-level="0" text:name="Text"/>
                      <text:sequence-decl text:display-outline-level="0" text:name="Drawing"/>
                  </text:sequence-decls>
                  <xsl:apply-templates select="node()"/>
              </office:text>
          </office:body>
      </xsl:template>

      <xsl:template match="h1">
          <text:h text:style-name="Heading_20_1"><xsl:apply-templates select="node()"/></text:h>
      </xsl:template>

      <xsl:template match="h2">
          <text:h text:style-name="Heading_20_2"><xsl:apply-templates select="node()"/></text:h>
      </xsl:template>

      <xsl:template match="h3">
          <text:h text:style-name="Heading_20_3"><xsl:apply-templates select="node()"/></text:h>
      </xsl:template>

      <xsl:template match="h4">
          <text:h text:style-name="Heading_20_4"><xsl:apply-templates select="node()"/></text:h>
      </xsl:template>


<xsl:template match="p"> <text:p text:style-name="Standard"><xsl:apply-templates select="node()"/></text:p> </xsl:template>


<xsl:template match="table"> <table:table table:name="Table1" table:style-name="Table1"> <table:table-column table:style-name="Table1.A" table:number-columns-repeated="2"/> <!-- FIXME: should not do this... instead simply apply on node() and have template matches for tr[th] --> <xsl:for-each select="tr[th]"> <table:table-header-rows> <table:table-row> <xsl:apply-templates select="th|td"/> </table:table-row> </table:table-header-rows> </xsl:for-each> <xsl:for-each select="tr[td]"> <table:table-row> <xsl:apply-templates select="td"/> </table:table-row> </xsl:for-each> </table:table> </xsl:template>

      <xsl:template match="th|td">
          <table:table-cell table:style-name="Table1.A1" office:value-type="string">
              <xsl:call-template name="text_applyer"/>
          </table:table-cell>
      </xsl:template>

      <xsl:template match="ul">
          <text:list text:style-name="L1">
              <!-- FIXME: should not do this...
                   instead simply apply on node() and have template matches for li -->
              <xsl:for-each select="li">
                  <text:list-item><xsl:call-template name="text_applyer"/></text:list-item>
              </xsl:for-each>
          </text:list>
      </xsl:template>

      <xsl:template name="text_applyer">
          <xsl:choose>
              <xsl:when test="text()"><text:p text:style-name="Standard"><xsl:value-of select="."/></text:p>
              </xsl:when>
              <xsl:otherwise><xsl:apply-templates select="node()"/></xsl:otherwise>
          </xsl:choose>
      </xsl:template>

      <xsl:template match="p">
          <text:p text:style-name="Standard"><xsl:apply-templates select="node()"/></text:p>
          <text:p text:style-name="Standard"></text:p>
      </xsl:template>

</xsl:stylesheet>

I normally use it with a Makefile ruleset like this:

  doc.odt: doc/content.xml
          bash -c 'cd doc ; zip -r ../doc.odt *'


doc/content.xml: html2oo.xslt doc.html xsltproc --html html2oo.xslt doc.html > doc/content.xml

  doc:
          [ -d doc ] || ( mkdir doc ; unzip -d doc doc.odt )


-- Nic Ferrier http://www.tapsellferrier.co.uk

Current Thread
  • [xsl] XSL to ODF/OOXML
    • Steve - Fri, 27 Apr 2007 13:11:55 -0400
      • <Possible follow-ups>
      • cknell - Fri, 27 Apr 2007 13:54:05 -0400
        • Joe Fawcett - Fri, 27 Apr 2007 19:02:02 +0100
          • Nic James Ferrier - Fri, 27 Apr 2007 20:12:33 +0100
          • Steve - Fri, 27 Apr 2007 15:13:24 -0400 <=
          • W Charlton - Mon, 30 Apr 2007 10:36:35 +0100
          • Steve - Mon, 30 Apr 2007 08:32:52 -0400
        • Steve - Fri, 27 Apr 2007 14:24:47 -0400
      • cknell - Fri, 27 Apr 2007 16:32:50 -0400