Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Transferring table styles using OpenOffice::OODoc

I'm attempting to copy the formatting of a table from one OpenOffice Writer file to another... I can tell that I'm writing the name of the style to the second document, but not the style data.

I suspect that this has something to do with the 'styles' part of the odfContainer, but I'm not clear on how to write this to the second document, especially because when I inspect the $style object in the debugger, it appears to be identical to the $doc object, which has supposedly loaded the 'content' part.

Here's what I've got so far...

#! /usr/bin/perl  use warnings; use strict;  use OpenOffice::OODoc;  my $file='mytest.odt'; my $outfile='doc2.odt';  # load input file my $container = odfContainer("$file"); $container->raw_export("styles.xml"); my $doc = odfDocument         (         container => $container,         part      => 'content'         );  my $style = odfDocument         (         container => $container,         part      => 'styles'         );  # load output file my $container2 = odfContainer( $outfile, create => 'text' ); $container2->raw_import("styles.xml");  my $doc2 = odfDocument         (         container => $container2,         part      => 'content'         );   # Load table from 'mytest.odt' my $table=$doc->getTable(0);  # Get style from first cell in $table my $headerstyle=$doc->getStyle( $doc->getCell($table, 0, 0) );  # Create table in $doc2 my $newtable=$doc2->appendTable('newtable', 1, 1, 'table-style' => $doc->getStyle($table) );  # Set style of first cell in $newtable to 'Table1.A1' $doc2->cellStyle( $newtable, 0, 0, 'Table1.A1' );  # Write 'doc2.odt' to disk $container2->save; 

The reason that I'm loading 'Table1.A1' as the cell style is that I found the following deep inside $table, when inspecting inside the debugger:

'next_sibling' => OpenOffice::OODoc::Element=HASH(0x102029250)    'att' => HASH(0x102029180)             'style:family' => 'table-cell'         'style:name' => 'Table1.A1'         'empty' => 0                        'first_child' => OpenOffice::OODoc::Element=HASH(0x1020294a0)       'att' => HASH(0x102029200)                'fo:background-color' => '#cccccc'          'fo:border' => '0.0069in solid #000000'          'fo:padding-bottom' => '0in'              'fo:padding-left' => '0.075in'            'fo:padding-right' => '0.075in'           'fo:padding-top' => '0in'                 'style:vertical-align' => 'top'           'style:writing-mode' => 'lr-tb'  

I know that the attributes match what I'm trying to copy, and I also know from experimentation that the 'getStyle' method returns the style::name attribute... I just don't know how to get from setting the style::name attribute using the cellStyle method to actually having the underlying data written in to the new document.

Edit:

Unzipping the OpenOffice file, I get several xml files:

  • settings.xml
  • styles.xml
  • content.xml

etc.

The 'styles' and 'content' parts of the OdfContainer correspond to styles.xml and content.xml. Styles.xml is a little like a css file, containing the style information for various header levels of an ODF file. Content.xml also contains style information, much like the css header in an html document.

Here's the style part of content.xml extracted from the odt file (actually one much like it... I didn't save the original).

<?xml version="1.0" encoding="utf-8"?> <office:document-content>    ...    <office:automatic-styles>     <style:style style:name="Table6" style:family="table" style:master-page-name="First_20_Page">       <style:table-properties style:width="6.9208in" style:page-number="auto" table:align="left" style:writing-mode="lr-tb" />     </style:style>     <style:style style:name="Table6.A" style:family="table-column">       <style:table-column-properties style:column-width="1.2729in" />     </style:style>     <style:style style:name="Table6.B" style:family="table-column">       <style:table-column-properties style:column-width="3.2604in" />     </style:style>     <style:style style:name="Table6.C" style:family="table-column">       <style:table-column-properties style:column-width="2.3875in" />     </style:style>     <style:style style:name="Table6.1" style:family="table-row">       <style:table-row-properties style:min-row-height="0.1597in" style:keep-together="true" fo:keep-together="auto" />     </style:style>     <style:style style:name="Table6.A1" style:family="table-cell">       <style:table-cell-properties           style:vertical-align="bottom"           fo:background-color="#cccccc"           fo:padding-left="0.075in"           fo:padding-right="0.075in"           fo:padding-top="0in"           fo:padding-bottom="0in"           fo:border-left="0.0069in solid #000000"           fo:border-right="none"           fo:border-top="0.0069in solid #000000"           fo:border-bottom="0.0069in solid #000000"           style:writing-mode="lr-tb">         <style:background-image />       </style:table-cell-properties>     </style:style>  ... 
  • style:name="Table6" describes the style for the current table,
  • style:name="Table6.A" describes the style for column A of this table,
  • style:name="Table6.A1" describes the style for the cell A1

Doing a raw export of 'content.xml' section of the input file, then a raw import in the output file does transfer data from one file to the other.

#! /usr/local/bin/perl  use warnings; use strict;  use OpenOffice::OODoc;  my $infile=$ARGV[0]; my $outfile='outfile.odt';  my $incontainer = odfContainer( $infile ); $incontainer->raw_export("content.xml");  my $outcontainer = odfContainer( $outfile, create => 'text' ); $outcontainer->raw_import("content.xml");  $outcontainer->save; 

Running oodoc.pl infile.odt, Then unzipping outfile.odt and inspecting content.xml does show that the style has been successfully transferred:

<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="2.3083in"     style:rel-column-width="21845*" /> </style:style> <style:style style:name="Table1.A1" style:family="table-cell">   <style:table-cell-properties        fo:background-color="#cccccc"        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:background-image />   </style:table-cell-properties> </style:style> 

Now that this has been done, I'll need to actually load and use the cell styles in $outcontainer.

like image 634
Barton Chittenden Avatar asked Jul 12 '11 21:07

Barton Chittenden


Video Answer


1 Answers

You did a raw import. The docs for that say "Remember too that the import is not actually carried out by OODoc::File until a save and the imported data is therefore not immediately available." I suggest you try $container2->save; and then re-load it right after importing styles and then see if Table.A1 shows up in doc2.odt's content.xml after the next save:

# load output file  my $container2 = odfContainer( $outfile, create => 'text' ); $container2->raw_import("styles.xml");  # Carry out the import and reload it with the new styles. $container2->save;  $container2 = odfContainer( $outfile );  my $doc2 = odfDocument         (         container => $container2,         part      => 'content'         );   # Load table from 'mytest.odt' my $table=$doc->getTable(0);  # Get style from first cell in $table my $headerstyle=$doc->getStyle( $doc->getCell($table, 0, 0) );  # Create table in $doc2 my $newtable=$doc2->appendTable('newtable', 1, 1, 'table-style' => $doc->getStyle($table) );  # Set style of first cell in $newtable to 'Table1.A1' $doc2->cellStyle( $newtable, 0, 0, 'Table1.A1' );  # Write 'doc2.odt' to disk $container2->save; 
like image 97
Dave Scotese Avatar answered Sep 20 '22 12:09

Dave Scotese