Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ public class DocxDocumentHandler

private Stack<ContainerProperties> paragraphsStack;

private Stack<Boolean> tableStack;

private Stack<SpanProperties> spansStack;

private HyperlinkRegistry hyperlinkRegistry;
Expand Down Expand Up @@ -109,6 +111,7 @@ public void startDocument()
this.paragraphsStack = new Stack<ContainerProperties>();
this.spansStack = new Stack<SpanProperties>();
this.addLineBreak = 0;
this.tableStack = new Stack<Boolean>();
}

public void endDocument()
Expand Down Expand Up @@ -320,10 +323,8 @@ private void processRunProperties( boolean isInsidePPr, boolean bold, boolean it
private void startParagraphIfNeeded()
throws IOException
{

if ( paragraphWasInserted && paragraphsStack.isEmpty() )
{
internalStartParagraph( null );
if (((paragraphWasInserted || !tableStack.isEmpty()) && paragraphsStack.isEmpty())) {
internalStartParagraph(null);
}
}

Expand Down Expand Up @@ -735,6 +736,8 @@ protected void doStartTable( TableProperties properties )
// w:tblGrid
// that's here temp writer is used.
pushTempWriter();
//Control if inside table
tableStack.push(true);
}

public void doEndTable( TableProperties properties )
Expand All @@ -751,7 +754,8 @@ public void doEndTable( TableProperties properties )
popTempWriter( startTable.toString() );
super.write( "</w:tbl>" );
// if table is inside a table cell, a paragraph is required.
super.write( "<w:p/>" );
super.write("<w:p/>");
tableStack.pop();
}

public void doStartTableRow( TableRowProperties properties )
Expand All @@ -773,14 +777,16 @@ public void doStartTableCell( TableCellProperties properties )
/*
* super.write( "<w:tcPr>" ); super.write( "<w:tcW w:w=\"0\" w:type=\"auto\" />" ); super.write( "</w:tcPr>" );
*/
internalStartParagraph( null );
if (properties != null) {
internalStartParagraph(properties);
}

}

public void doEndTableCell()
throws IOException
throws IOException
{
endParagraph();
endParagraphIfNeeded();
super.write( "</w:tc>" );
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,32 @@ public void testTable()
handler.getTextEnd() );
}

@Test
public void testStyledTable()
throws Exception {
IContext context = new MockContext();
BufferedElement parent = null;

ITextStylingTransformer formatter = HTMLTextStylingTransformer.INSTANCE;
IDocumentHandler handler = new DocxDocumentHandler(parent, context, "word/document.xml");
formatter.transform("<table><tbody>"
+ "<tr><td style='name:Standard'>A</td><td>B</td></tr>"
+ "<tr><td style='name:Standard'>C</td><td>D</td></tr>"
+ "<tr><td style='name:Standard'>E</td><td>F</td></tr>"
+ "</tbody></table>",
handler);

Assert.assertEquals("", handler.getTextBefore());
Assert.assertEquals("", handler.getTextBody());
Assert.assertEquals("<w:tbl>"
+ "<w:tblGrid><w:gridCol w:w=\"2994\" /><w:gridCol w:w=\"2994\" /></w:tblGrid>"
+ "<w:tr><w:tc><w:p><w:pPr><w:pStyle w:val=\"Standard\" /></w:pPr><w:r><w:t xml:space=\"preserve\" >A</w:t></w:r></w:p></w:tc><w:tc><w:p><w:r><w:t xml:space=\"preserve\" >B</w:t></w:r></w:p></w:tc></w:tr>"
+ "<w:tr><w:tc><w:p><w:pPr><w:pStyle w:val=\"Standard\" /></w:pPr><w:r><w:t xml:space=\"preserve\" >C</w:t></w:r></w:p></w:tc><w:tc><w:p><w:r><w:t xml:space=\"preserve\" >D</w:t></w:r></w:p></w:tc></w:tr>"
+ "<w:tr><w:tc><w:p><w:pPr><w:pStyle w:val=\"Standard\" /></w:pPr><w:r><w:t xml:space=\"preserve\" >E</w:t></w:r></w:p></w:tc><w:tc><w:p><w:r><w:t xml:space=\"preserve\" >F</w:t></w:r></w:p></w:tc></w:tr>"
+ "</w:tbl><w:p/>",
handler.getTextEnd());
}

@Test
public void testAll()
throws Exception
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,21 @@ public class ODTDocumentHandler

private boolean insideHeader = false;

private Stack<Boolean> tableStack;

private Stack<Integer> spanStack;

/**
* Stores each nested tag added to the document.
* Required to verify if a new paragraph can be added.
* Paragraphs cannot be direct children of another paragraph, but they
* can, sometimes, be nested if there are other tags between them, like
* a list and a list-item.
*
* Relevant document: http://docs.oasis-open.org/office/v1.2/os/OpenDocument-v1.2-os-part1.html#__RefHeading__1415138_253892949
*/
private Stack<String> nestedTagStack;

private int listDepth = 0;

private List<Boolean> lastItemAlreadyClosed = new ArrayList<Boolean>();
Expand All @@ -75,6 +88,8 @@ public void startDocument()
{
this.paragraphsStack = new Stack<Boolean>();
this.spanStack = new Stack<Integer>();
this.tableStack = new Stack<Boolean>();
this.nestedTagStack = new Stack<String>();
}

public void endDocument()
Expand Down Expand Up @@ -237,6 +252,8 @@ private void internalStartSpan( String styleName, boolean push )
{
spanStack.push( 1 );
}

pushNestedTag("span");
}

private void internalEndSpan()
Expand All @@ -249,27 +266,30 @@ private void internalEndSpan()
while ( depth > 0 )
{
super.write( "</text:span>" );
popNestedTag("span");
depth--;
}
}

private void startParagraphIfNeeded()
throws IOException
{

if ( ( paragraphWasInserted && paragraphsStack.isEmpty() ) || closeHeader )
{
if (((paragraphWasInserted || !tableStack.isEmpty()) && paragraphsStack.isEmpty()) || closeHeader) {
internalStartParagraph( false, (String) null );
}
}

public void startParagraph( ParagraphProperties properties )
throws IOException
{
if ( paragraphsStack.isEmpty() || !paragraphsStack.peek() )
if ( !paragraphsStack.isEmpty() && !paragraphsStack.peek() )
{
super.setTextLocation( TextLocation.End );
internalStartParagraph( false, properties );
internalEndParagraph();
}

if(nestedTagStack.isEmpty() || !"p".equals(nestedTagStack.peek())) {
super.setTextLocation(TextLocation.End);
internalStartParagraph(false, properties);
}
}

Expand Down Expand Up @@ -304,15 +324,6 @@ else if ( properties.isPageBreakBefore() )
}
}
internalStartParagraph( containerIsList, styleName );

// if ( properties != null )
// {
// // Remove "span" added by internalStartParagraph
// // spanStack.pop();
//
// // Process properties
// // startSpan( properties );
// }
}

private void internalStartParagraph( boolean containerIsList, String styleName )
Expand All @@ -335,6 +346,7 @@ private void internalStartParagraph( boolean containerIsList, String styleName )

// Put a 0 in the stack, endSpan is called when a paragraph is ended
spanStack.push( 0 );
pushNestedTag("p");
}

private void internalEndParagraph()
Expand All @@ -345,8 +357,10 @@ private void internalEndParagraph()
// Close any spans from paragraph style
internalEndSpan();


super.write( "</text:p>" );
paragraphsStack.pop();
popNestedTag("p");
}
}

Expand All @@ -359,6 +373,7 @@ public void startHeading( int level, HeaderProperties properties )
+ level + "\">" );
insideHeader = true;
closeHeader = false;
pushNestedTag("h");
}

public void endHeading( int level )
Expand All @@ -367,6 +382,7 @@ public void endHeading( int level )
super.write( "</text:h>" );
insideHeader = false;
closeHeader = true;
popNestedTag("h");
// startParagraph();
}

Expand Down Expand Up @@ -427,6 +443,7 @@ protected void internalStartList( String style )
super.write( "<text:list>" );
}
listDepth++;
pushNestedTag("list");
}

protected void internalEndList()
Expand All @@ -438,11 +455,14 @@ protected void internalEndList()
{
// startParagraph();
}

popNestedTag("list");
}

public void startListItem( ListItemProperties properties )
throws IOException
{
pushNestedTag("list-item");
if ( itemStyle != null )
{
super.write( "<text:list-item text:style-name=\"" + itemStyle + "\">" );
Expand All @@ -453,6 +473,8 @@ public void startListItem( ListItemProperties properties )
super.write( "<text:list-item>" );
internalStartParagraph( true, (String) null );
}


}

public void endListItem()
Expand All @@ -468,6 +490,7 @@ public void endListItem()
}
endParagraphIfNeeded();
super.write( "</text:list-item>" );
popNestedTag("list-item");
}

public void startSpan( SpanProperties properties )
Expand Down Expand Up @@ -515,6 +538,8 @@ protected void doStartTable( TableProperties properties )
// table:table-column
// that's here temp writer is used.
pushTempWriter();
//Control if inside table
tableStack.push(true);
}

public void doEndTable( TableProperties properties )
Expand All @@ -529,32 +554,52 @@ public void doEndTable( TableProperties properties )
startTable.append( "\" >" );
startTable.append( "</table:table-column>" );
popTempWriter( startTable.toString() );
super.write( "</table:table>" );
super.write("</table:table>");
tableStack.pop();
}

protected void doStartTableRow( TableRowProperties properties )
throws IOException
{
super.write( "<table:table-row>" );
pushNestedTag("table-row");
}

protected void doEndTableRow()
throws IOException
{
super.write( "</table:table-row>" );
popNestedTag("table-row");
}

protected void doStartTableCell( TableCellProperties properties )
throws IOException
{
super.write( "<table:table-cell>" );
internalStartParagraph( false, (String) null );
super.write("<table:table-cell>");
pushNestedTag("table-cell");
if (properties != null) {
internalStartParagraph(false, styleGen.getTextStyleName(properties));
}
}

public void doEndTableCell()
throws IOException
throws IOException
{
endParagraph();
super.write( "</table:table-cell>" );
endParagraphIfNeeded();
super.write("</table:table-cell>");
popNestedTag("table-cell");
}

private void popNestedTag(String tag) {
String stackTag = nestedTagStack.peek();
if(stackTag.equals(tag)) {
nestedTagStack.pop();
} else {
throw new RuntimeException("Invalid nested tag. Should be <" + tag + "> found <" + stackTag + ">.");
}
}

private void pushNestedTag(String tag) {
nestedTagStack.push(tag);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -775,7 +775,7 @@ public void testHeaderAndTextAndParagraph()

Assert.assertEquals( "", handler.getTextBefore() );
Assert.assertEquals( "", handler.getTextBody() );
Assert.assertEquals( "<text:h text:style-name=\"Heading_20_1\" text:outline-level=\"1\">Title1</text:h><text:p><text:span text:style-name=\"XDocReport_EmptyText\" >text</text:span><text:p><text:span text:style-name=\"XDocReport_EmptyText\" >paragraph</text:span></text:p></text:p>",
Assert.assertEquals( "<text:h text:style-name=\"Heading_20_1\" text:outline-level=\"1\">Title1</text:h><text:p><text:span text:style-name=\"XDocReport_EmptyText\" >text</text:span></text:p><text:p><text:span text:style-name=\"XDocReport_EmptyText\" >paragraph</text:span></text:p>",
handler.getTextEnd() );
}

Expand Down Expand Up @@ -1057,7 +1057,7 @@ public void testSpansInP()

@Test
public void testTable()
throws Exception
throws Exception
{
IContext context = new MockContext();
BufferedElement parent = null;
Expand All @@ -1075,10 +1075,36 @@ public void testTable()
Assert.assertEquals( "", handler.getTextBody() );
Assert.assertEquals( "<table:table>"
+ "<table:table-column table:number-columns-repeated=\"2\" ></table:table-column>"
+ "<table:table-row><table:table-cell><text:p><text:span text:style-name=\"XDocReport_EmptyText\" >A</text:span></text:p></table:table-cell><table:table-cell><text:p><text:span text:style-name=\"XDocReport_EmptyText\" >B</text:span></text:p></table:table-cell></table:table-row>"
+ "<table:table-row><table:table-cell><text:p><text:span text:style-name=\"XDocReport_EmptyText\" >C</text:span></text:p></table:table-cell><table:table-cell><text:p><text:span text:style-name=\"XDocReport_EmptyText\" >D</text:span></text:p></table:table-cell></table:table-row>"
+ "<table:table-row><table:table-cell><text:p><text:span text:style-name=\"XDocReport_EmptyText\" >E</text:span></text:p></table:table-cell><table:table-cell><text:p><text:span text:style-name=\"XDocReport_EmptyText\" >F</text:span></text:p></table:table-cell></table:table-row>"
+ "</table:table>",
+ "<table:table-row><table:table-cell><text:p><text:span text:style-name=\"XDocReport_EmptyText\" >A</text:span></text:p></table:table-cell><table:table-cell><text:p><text:span text:style-name=\"XDocReport_EmptyText\" >B</text:span></text:p></table:table-cell></table:table-row>"
+ "<table:table-row><table:table-cell><text:p><text:span text:style-name=\"XDocReport_EmptyText\" >C</text:span></text:p></table:table-cell><table:table-cell><text:p><text:span text:style-name=\"XDocReport_EmptyText\" >D</text:span></text:p></table:table-cell></table:table-row>"
+ "<table:table-row><table:table-cell><text:p><text:span text:style-name=\"XDocReport_EmptyText\" >E</text:span></text:p></table:table-cell><table:table-cell><text:p><text:span text:style-name=\"XDocReport_EmptyText\" >F</text:span></text:p></table:table-cell></table:table-row>"
+ "</table:table>",
handler.getTextEnd() );
}

@Test
public void testStyledTable()
throws Exception {
IContext context = new MockContext();
BufferedElement parent = null;

ITextStylingTransformer formatter = HTMLTextStylingTransformer.INSTANCE;
IDocumentHandler handler = new ODTDocumentHandler(parent, context, "content.xml");
formatter.transform("<table><tbody>"
+ "<tr><td style='name:Standard'>A</td><td>B</td></tr>"
+ "<tr><td style='name:Standard'>C</td><td>D</td></tr>"
+ "<tr><td style='name:Standard'>E</td><td>F</td></tr>"
+ "</tbody></table>",
handler);

Assert.assertEquals("", handler.getTextBefore());
Assert.assertEquals("", handler.getTextBody());
Assert.assertEquals("<table:table>"
+ "<table:table-column table:number-columns-repeated=\"2\" ></table:table-column>"
+ "<table:table-row><table:table-cell><text:p text:style-name=\"Standard\"><text:span text:style-name=\"XDocReport_EmptyText\" >A</text:span></text:p></table:table-cell><table:table-cell><text:p><text:span text:style-name=\"XDocReport_EmptyText\" >B</text:span></text:p></table:table-cell></table:table-row>"
+ "<table:table-row><table:table-cell><text:p text:style-name=\"Standard\"><text:span text:style-name=\"XDocReport_EmptyText\" >C</text:span></text:p></table:table-cell><table:table-cell><text:p><text:span text:style-name=\"XDocReport_EmptyText\" >D</text:span></text:p></table:table-cell></table:table-row>"
+ "<table:table-row><table:table-cell><text:p text:style-name=\"Standard\"><text:span text:style-name=\"XDocReport_EmptyText\" >E</text:span></text:p></table:table-cell><table:table-cell><text:p><text:span text:style-name=\"XDocReport_EmptyText\" >F</text:span></text:p></table:table-cell></table:table-row>"
+ "</table:table>",
handler.getTextEnd());
}
}
Loading