Fix table processing. Spanned columns / different width / spanned rows are correcly rendered in HTML and FO now
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1149593 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
e86ef4f8bf
commit
7cbdf296fb
@ -41,6 +41,8 @@ import org.apache.poi.hwpf.usermodel.Picture;
|
|||||||
import org.apache.poi.hwpf.usermodel.Range;
|
import org.apache.poi.hwpf.usermodel.Range;
|
||||||
import org.apache.poi.hwpf.usermodel.Section;
|
import org.apache.poi.hwpf.usermodel.Section;
|
||||||
import org.apache.poi.hwpf.usermodel.Table;
|
import org.apache.poi.hwpf.usermodel.Table;
|
||||||
|
import org.apache.poi.hwpf.usermodel.TableCell;
|
||||||
|
import org.apache.poi.hwpf.usermodel.TableRow;
|
||||||
import org.apache.poi.util.POILogFactory;
|
import org.apache.poi.util.POILogFactory;
|
||||||
import org.apache.poi.util.POILogger;
|
import org.apache.poi.util.POILogger;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
@ -86,6 +88,68 @@ public abstract class AbstractWordConverter
|
|||||||
return fontReplacer;
|
return fontReplacer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected int getNumberColumnsSpanned( int[] tableCellEdges,
|
||||||
|
int currentEdgeIndex, TableCell tableCell )
|
||||||
|
{
|
||||||
|
int nextEdgeIndex = currentEdgeIndex;
|
||||||
|
int colSpan = 0;
|
||||||
|
int cellRightEdge = tableCell.getLeftEdge() + tableCell.getWidth();
|
||||||
|
while ( tableCellEdges[nextEdgeIndex] < cellRightEdge )
|
||||||
|
{
|
||||||
|
colSpan++;
|
||||||
|
nextEdgeIndex++;
|
||||||
|
}
|
||||||
|
return colSpan;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int getNumberRowsSpanned( Table table, int currentRowIndex,
|
||||||
|
int currentColumnIndex, TableCell tableCell )
|
||||||
|
{
|
||||||
|
if ( !tableCell.isFirstVerticallyMerged() )
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
final int numRows = table.numRows();
|
||||||
|
|
||||||
|
int count = 1;
|
||||||
|
for ( int r1 = currentRowIndex + 1; r1 < numRows; r1++ )
|
||||||
|
{
|
||||||
|
TableRow nextRow = table.getRow( r1 );
|
||||||
|
if ( nextRow.numCells() < currentColumnIndex )
|
||||||
|
break;
|
||||||
|
TableCell nextCell = nextRow.getCell( currentColumnIndex );
|
||||||
|
if ( !nextCell.isVerticallyMerged()
|
||||||
|
|| nextCell.isFirstVerticallyMerged() )
|
||||||
|
break;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int getTableCellEdgesIndexSkipCount( Table table, int r,
|
||||||
|
int[] tableCellEdges, int currentEdgeIndex, int c,
|
||||||
|
TableCell tableCell )
|
||||||
|
{
|
||||||
|
TableCell upperCell = null;
|
||||||
|
for ( int r1 = r - 1; r1 >= 0; r1-- )
|
||||||
|
{
|
||||||
|
final TableCell prevCell = table.getRow( r1 ).getCell( c );
|
||||||
|
if ( prevCell != null && prevCell.isFirstVerticallyMerged() )
|
||||||
|
{
|
||||||
|
upperCell = prevCell;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( upperCell == null )
|
||||||
|
{
|
||||||
|
logger.log( POILogger.WARN, "First vertically merged cell for ",
|
||||||
|
tableCell, " not found" );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getNumberColumnsSpanned( tableCellEdges, currentEdgeIndex,
|
||||||
|
tableCell );
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract void outputCharacters( Element block,
|
protected abstract void outputCharacters( Element block,
|
||||||
CharacterRun characterRun, String text );
|
CharacterRun characterRun, String text );
|
||||||
|
|
||||||
@ -211,7 +275,7 @@ public abstract class AbstractWordConverter
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ( text.endsWith( "\r" )
|
if ( text.endsWith( "\r" )
|
||||||
|| ( text.charAt( text.length() - 1 ) == BEL_MARK && currentTableLevel != 0 ) )
|
|| ( text.charAt( text.length() - 1 ) == BEL_MARK && currentTableLevel != Integer.MIN_VALUE ) )
|
||||||
text = text.substring( 0, text.length() - 1 );
|
text = text.substring( 0, text.length() - 1 );
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -239,7 +303,8 @@ public abstract class AbstractWordConverter
|
|||||||
// Non-required hyphens to zero-width space
|
// Non-required hyphens to zero-width space
|
||||||
stringBuilder.append( UNICODECHAR_ZERO_WIDTH_SPACE );
|
stringBuilder.append( UNICODECHAR_ZERO_WIDTH_SPACE );
|
||||||
}
|
}
|
||||||
else
|
else if ( charChar > 0x20 || charChar == 0x09
|
||||||
|
|| charChar == 0x0A || charChar == 0x0D )
|
||||||
{
|
{
|
||||||
stringBuilder.append( charChar );
|
stringBuilder.append( charChar );
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,28 @@ import org.w3c.dom.Text;
|
|||||||
public class WordToFoConverter extends AbstractWordConverter
|
public class WordToFoConverter extends AbstractWordConverter
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds properties values, applied to current <tt>fo:block</tt> element.
|
||||||
|
* Those properties shall not be doubled in children <tt>fo:inline</tt>
|
||||||
|
* elements.
|
||||||
|
*/
|
||||||
|
private static class BlockProperies
|
||||||
|
{
|
||||||
|
final boolean pBold;
|
||||||
|
final String pFontName;
|
||||||
|
final int pFontSize;
|
||||||
|
final boolean pItalic;
|
||||||
|
|
||||||
|
public BlockProperies( String pFontName, int pFontSize, boolean pBold,
|
||||||
|
boolean pItalic )
|
||||||
|
{
|
||||||
|
this.pFontName = pFontName;
|
||||||
|
this.pFontSize = pFontSize;
|
||||||
|
this.pBold = pBold;
|
||||||
|
this.pItalic = pItalic;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static final POILogger logger = POILogFactory
|
private static final POILogger logger = POILogFactory
|
||||||
.getLogger( WordToFoConverter.class );
|
.getLogger( WordToFoConverter.class );
|
||||||
|
|
||||||
@ -513,26 +535,22 @@ public class WordToFoConverter extends AbstractWordConverter
|
|||||||
{
|
{
|
||||||
TableCell tableCell = tableRow.getCell( c );
|
TableCell tableCell = tableRow.getCell( c );
|
||||||
|
|
||||||
if ( tableCell.isMerged() && !tableCell.isFirstMerged() )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if ( tableCell.isVerticallyMerged()
|
if ( tableCell.isVerticallyMerged()
|
||||||
&& !tableCell.isFirstVerticallyMerged() )
|
&& !tableCell.isFirstVerticallyMerged() )
|
||||||
|
{
|
||||||
|
currentEdgeIndex += getTableCellEdgesIndexSkipCount( table,
|
||||||
|
r, tableCellEdges, currentEdgeIndex, c, tableCell );
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
Element tableCellElement = foDocumentFacade.createTableCell();
|
Element tableCellElement = foDocumentFacade.createTableCell();
|
||||||
WordToFoUtils.setTableCellProperties( tableRow, tableCell,
|
WordToFoUtils.setTableCellProperties( tableRow, tableCell,
|
||||||
tableCellElement, r == 0, r == tableRows - 1, c == 0,
|
tableCellElement, r == 0, r == tableRows - 1, c == 0,
|
||||||
c == rowCells - 1 );
|
c == rowCells - 1 );
|
||||||
|
|
||||||
int colSpan = 0;
|
int colSpan = getNumberColumnsSpanned( tableCellEdges,
|
||||||
int cellRightEdge = tableCell.getLeftEdge()
|
currentEdgeIndex, tableCell );
|
||||||
+ tableCell.getWidth();
|
currentEdgeIndex += colSpan;
|
||||||
while ( tableCellEdges[currentEdgeIndex] < cellRightEdge )
|
|
||||||
{
|
|
||||||
colSpan++;
|
|
||||||
currentEdgeIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( colSpan == 0 )
|
if ( colSpan == 0 )
|
||||||
continue;
|
continue;
|
||||||
@ -541,24 +559,11 @@ public class WordToFoConverter extends AbstractWordConverter
|
|||||||
tableCellElement.setAttribute( "number-columns-spanned",
|
tableCellElement.setAttribute( "number-columns-spanned",
|
||||||
String.valueOf( colSpan ) );
|
String.valueOf( colSpan ) );
|
||||||
|
|
||||||
if ( tableCell.isFirstVerticallyMerged() )
|
final int rowSpan = getNumberRowsSpanned( table, r, c,
|
||||||
{
|
tableCell );
|
||||||
int count = 0;
|
if ( rowSpan > 1 )
|
||||||
for ( int r1 = r; r1 < tableRows; r1++ )
|
tableCellElement.setAttribute( "number-rows-spanned",
|
||||||
{
|
String.valueOf( rowSpan ) );
|
||||||
TableRow nextRow = table.getRow( r1 );
|
|
||||||
if ( nextRow.numCells() < c )
|
|
||||||
break;
|
|
||||||
TableCell nextCell = nextRow.getCell( c );
|
|
||||||
if ( nextCell.isVerticallyMerged() )
|
|
||||||
count++;
|
|
||||||
if ( !nextCell.isVerticallyMerged() )
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if ( count > 1 )
|
|
||||||
tableCellElement.setAttribute( "number-rows-spanned",
|
|
||||||
String.valueOf( count ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
processParagraphes( wordDocument, tableCellElement, tableCell,
|
processParagraphes( wordDocument, tableCellElement, tableCell,
|
||||||
table.getTableLevel() );
|
table.getTableLevel() );
|
||||||
@ -572,17 +577,21 @@ public class WordToFoConverter extends AbstractWordConverter
|
|||||||
tableRowElement.appendChild( tableCellElement );
|
tableRowElement.appendChild( tableCellElement );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( tableRow.isTableHeader() )
|
if ( tableRowElement.hasChildNodes() )
|
||||||
{
|
{
|
||||||
tableHeader.appendChild( tableRowElement );
|
if ( tableRow.isTableHeader() )
|
||||||
}
|
{
|
||||||
else
|
tableHeader.appendChild( tableRowElement );
|
||||||
{
|
}
|
||||||
tableBody.appendChild( tableRowElement );
|
else
|
||||||
|
{
|
||||||
|
tableBody.appendChild( tableRowElement );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final Element tableElement = foDocumentFacade.createTable();
|
final Element tableElement = foDocumentFacade.createTable();
|
||||||
|
tableElement.setAttribute( "table-layout", "fixed" );
|
||||||
if ( tableHeader.hasChildNodes() )
|
if ( tableHeader.hasChildNodes() )
|
||||||
{
|
{
|
||||||
tableElement.appendChild( tableHeader );
|
tableElement.appendChild( tableHeader );
|
||||||
@ -602,26 +611,4 @@ public class WordToFoConverter extends AbstractWordConverter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds properties values, applied to current <tt>fo:block</tt> element.
|
|
||||||
* Those properties shall not be doubled in children <tt>fo:inline</tt>
|
|
||||||
* elements.
|
|
||||||
*/
|
|
||||||
private static class BlockProperies
|
|
||||||
{
|
|
||||||
final boolean pBold;
|
|
||||||
final String pFontName;
|
|
||||||
final int pFontSize;
|
|
||||||
final boolean pItalic;
|
|
||||||
|
|
||||||
public BlockProperies( String pFontName, int pFontSize, boolean pBold,
|
|
||||||
boolean pItalic )
|
|
||||||
{
|
|
||||||
this.pFontName = pFontName;
|
|
||||||
this.pFontSize = pFontSize;
|
|
||||||
this.pBold = pBold;
|
|
||||||
this.pItalic = pItalic;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -61,6 +61,22 @@ import static org.apache.poi.hwpf.converter.AbstractWordUtils.TWIPS_PER_INCH;
|
|||||||
public class WordToHtmlConverter extends AbstractWordConverter
|
public class WordToHtmlConverter extends AbstractWordConverter
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds properties values, applied to current <tt>p</tt> element. Those
|
||||||
|
* properties shall not be doubled in children <tt>span</tt> elements.
|
||||||
|
*/
|
||||||
|
private static class BlockProperies
|
||||||
|
{
|
||||||
|
final String pFontName;
|
||||||
|
final int pFontSize;
|
||||||
|
|
||||||
|
public BlockProperies( String pFontName, int pFontSize )
|
||||||
|
{
|
||||||
|
this.pFontName = pFontName;
|
||||||
|
this.pFontSize = pFontSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static final POILogger logger = POILogFactory
|
private static final POILogger logger = POILogFactory
|
||||||
.getLogger( WordToHtmlConverter.class );
|
.getLogger( WordToHtmlConverter.class );
|
||||||
|
|
||||||
@ -584,7 +600,11 @@ public class WordToHtmlConverter extends AbstractWordConverter
|
|||||||
|
|
||||||
if ( tableCell.isVerticallyMerged()
|
if ( tableCell.isVerticallyMerged()
|
||||||
&& !tableCell.isFirstVerticallyMerged() )
|
&& !tableCell.isFirstVerticallyMerged() )
|
||||||
|
{
|
||||||
|
currentEdgeIndex += getTableCellEdgesIndexSkipCount( table,
|
||||||
|
r, tableCellEdges, currentEdgeIndex, c, tableCell );
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
Element tableCellElement;
|
Element tableCellElement;
|
||||||
if ( tableRow.isTableHeader() )
|
if ( tableRow.isTableHeader() )
|
||||||
@ -601,42 +621,22 @@ public class WordToHtmlConverter extends AbstractWordConverter
|
|||||||
r == 0, r == tableRows - 1, c == 0, c == rowCells - 1,
|
r == 0, r == tableRows - 1, c == 0, c == rowCells - 1,
|
||||||
tableCellStyle );
|
tableCellStyle );
|
||||||
|
|
||||||
int colSpan = 0;
|
int colSpan = getNumberColumnsSpanned( tableCellEdges,
|
||||||
int cellRightEdge = tableCell.getLeftEdge()
|
currentEdgeIndex, tableCell );
|
||||||
+ tableCell.getWidth();
|
currentEdgeIndex += colSpan;
|
||||||
while ( tableCellEdges[currentEdgeIndex] < cellRightEdge )
|
|
||||||
{
|
|
||||||
colSpan++;
|
|
||||||
currentEdgeIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( colSpan == 0 )
|
if ( colSpan == 0 )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ( colSpan != 1 )
|
if ( colSpan != 1 )
|
||||||
{
|
|
||||||
tableCellElement.setAttribute( "colspan",
|
tableCellElement.setAttribute( "colspan",
|
||||||
String.valueOf( colSpan ) );
|
String.valueOf( colSpan ) );
|
||||||
}
|
|
||||||
|
|
||||||
if ( tableCell.isFirstVerticallyMerged() )
|
final int rowSpan = getNumberRowsSpanned( table, r, c,
|
||||||
{
|
tableCell );
|
||||||
int count = 1;
|
if ( rowSpan > 1 )
|
||||||
for ( int r1 = r + 1; r1 < tableRows; r1++ )
|
tableCellElement.setAttribute( "rowspan",
|
||||||
{
|
String.valueOf( rowSpan ) );
|
||||||
TableRow nextRow = table.getRow( r1 );
|
|
||||||
if ( nextRow.numCells() < c )
|
|
||||||
break;
|
|
||||||
TableCell nextCell = nextRow.getCell( c );
|
|
||||||
if ( !nextCell.isVerticallyMerged()
|
|
||||||
|| nextCell.isFirstVerticallyMerged() )
|
|
||||||
break;
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
if ( count > 1 )
|
|
||||||
tableCellElement.setAttribute( "rowspan",
|
|
||||||
String.valueOf( count ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
processParagraphes( hwpfDocument, tableCellElement, tableCell,
|
processParagraphes( hwpfDocument, tableCellElement, tableCell,
|
||||||
table.getTableLevel() );
|
table.getTableLevel() );
|
||||||
@ -695,20 +695,4 @@ public class WordToHtmlConverter extends AbstractWordConverter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds properties values, applied to current <tt>p</tt> element. Those
|
|
||||||
* properties shall not be doubled in children <tt>span</tt> elements.
|
|
||||||
*/
|
|
||||||
private static class BlockProperies
|
|
||||||
{
|
|
||||||
final String pFontName;
|
|
||||||
final int pFontSize;
|
|
||||||
|
|
||||||
public BlockProperies( String pFontName, int pFontSize )
|
|
||||||
{
|
|
||||||
this.pFontName = pFontName;
|
|
||||||
this.pFontSize = pFontSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user