Hi Team,
I’m using AsposeWordsForJava 13.5.
I created a table. I know there is no concept of row in word just for understanding purpose I have used it below.
Table
row1
cell cell(span 4)
row2 (span 2)
cell cell(span 4)
row3
cell (span 4)
The first cell in row 2 is being merged vertically with the next row 1st cell. But for the merge part, the table/cell border is missing. See attached word and pdf output. I’m also attaching the standalone code to replicate the issue.
Thanks,
Kumar
Hi Kumar,
Thanks for your inquiry. Microsoft Word displays two cells in first row of table but there are actually six cells present in Aspose.Words’ DOM. Same is the case with second and third rows. To be able to set borders for each table cell, please try run the following code:
private void tableFromXhtml() throws Exception
{
// ....
// ....
currentCell.getCellFormat().setWidth(309);
currentCell.getCellFormat().setPreferredWidth( PreferredWidth . fromPoints (309));
table.setAllowAutoFit(true);
NodeCollection cells = table.getChildNodes(NodeType.CELL, true);
for (Cell cell : (Iterable<Cell>)cells){
cell.getCellFormat().getBorders().setLineStyle(1);
cell.getCellFormat().getBorders().setLineWidth(1);
}
}
I hope, this helps.
Best regards,
Hi Awais,
Microsoft Word displays two cells in first row of table but there are actually six cells present in Aspose.WordsÆ DOM.
I understand this point as there is a colspan of 5 for the 2nd cell, which makes it 6 cells.
The issue is with the border for 1st cell of 2nd row, which is merged with 1st cell of 3rd row. The left and bottom border is missing for the merged cell part.
cell.getCellFormat().getBorders().setLineStyle(1);
cell.getCellFormat().getBorders().setLineWidth(1);
I cannot use this setting because, the line style for the merged cell will be different for different cases. Same is with the line width, color and other properties. Aspose should inherit these properties for the merged cell (parent/1st-merged cell), i.e, the properties for 1st cell of 3rd row (merged cell) should be inherited from 1st cell of 2nd row, as per my example.
Please let me know if this is not clear.
This seems to be a defect in Aspose Words.
Thanks,
Kumar
Hi Kumar,
Thanks for the additional information. Aspose.Words mimics the behaviour of Microsoft Word i.e. consider a cell has all four borders (top, bottom, left, right) and when you vertically merge it with the cell in the following row, the resulting merged cell will lose borders. Moreover, the actions that can be performed with merged cells using Aspose.Words are the same as the ones you can perform using Microsoft Word. If we can help you with anything else, please feel free to ask.
PS: Please watch this
video to learn how to create Table from scratch, insert content inside this table and apply different formatting using DocumentBuilder class. I hope, this helps.
Best regards,
Hi Awais,
Thanks for additional info.
>>> when you vertically merge it with the cell in the following row, the resulting merged cell will lose borders.
I guess there should be a code to fix such table/cells.
We’re using “mergedCell.getPreviousSibling()” to copy border properties like “style/width/color” for the merged cell for horizontal merge (cell span).
For vertical merge, is there any Aspose Cell API to get mergedCell’s previous rows matching cell so that I could copy border properties from it?
Or any other way like table.getChildNodes that you mentioned earlier, but read properties from previous row matching cell?
Thanks,
Kumar
Hi Kumar,
Thanks for your inquiry. Sure, you can copy border properties and whole formatting of CellFormat of one cell to another cell. Please see the following code snippet:
CopyFormatting(tab.FirstRow.FirstCell.CellFormat,
tab.FirstRow.LastCell.CellFormat);
public static void CopyFormatting(Object source, Object dest)
{
if (source.GetType() != dest.GetType())
throw new ArgumentException("All objects must be of the same type");
// Iterate through each property in the source object.
foreach(PropertyInfo prop in source.GetType().GetProperties())
{
// Skip indexed access items. Skip setting the internals of a style as these should not be changed.
if (prop.Name == "Item" || prop.Name == "Style")
continue;
object value;
// Wrap this call as it can throw an exception. Skip if thrown
try
{
value = prop.GetValue(source, null);
}
catch (Exception)
{
continue;
}
// Skip if value can not be retrieved.
if (value != null)
{
// If this property returns a class which belongs to the
if (value.GetType().IsClass && prop.GetGetMethod().ReturnType.Assembly.ManifestModule.Name == "Aspose.Words.dll")
{
// Recurse into this class.
CopyFormatting(prop.GetValue(source, null), prop.GetValue(dest, null));
}
else if (prop.CanWrite)
{
prop.SetValue(dest, prop.GetValue(source, null), null);
}
}
}
}
I hope, this helps.
Best regards,
Hi Awais,
Thanks for the code. But it is bit different than what I’m looking for. However, this one helps too.
Once the entire table model is created in java memory, is there a way to loop over table row / cells and find the cells with vertical merge and then copy the properties from the first cell for vertical merge.
This is easier with horizontal merge, since cell.getPreviousSibling() while building the table model itself.
Thanks,
Kumar
Hi Kumar,
Thanks for your inquiry. To check if a cell is part of a sequence of merged cells, we simply check the CellFormat.HorizontalMerge and CellFormat.VerticalMerge properties. For more details, please read the following article:
https://docs.aspose.com/words/java/working-with-merged-cells/
Best regards,
Thanks Awais. I’ll try this and get back.
Hi Awais,
Do you recommend this method?
This will called right after -
Cell cell = docBuilder.insertCell();
docBuilder.getCellFormat().setVerticalMerge(CellMerge.PREVIOUS);
Cell parentCell = getParentMatchingCell(cell, table);
// Now copy border properties from "parentCell" to "cell".
private Cell getParentMatchingCell(Cell currentCell, Table table)
{
Cell parentCell = null;
try
{
if (currentCell == null || currentCell.getParentRow() == null)
{
return parentCell;
}
else
{
Row currentRow = currentCell.getParentRow();
int currentCellIndex = -1;
for (int i = 0; i < currentRow.getCells().getCount(); i++)
{
if (currentCell.equals(currentRow.getCells().get(i)))
{
currentCellIndex = i;
break;
}
}
if (currentCellIndex != -1)
{
Row parentRow = null;
for (int i = 0; i < table.getRows().getCount(); i++)
{
if (currentRow.equals(table.getRows().get(i)))
{
parentRow = table.getRows().get(i - 1);
break;
}
}
parentCell = parentRow.getCells().get(currentCellIndex);
}
}
}
catch (Exception e)
{
// ignore?
}
return parentCell;
}
Thanks,
Kumar
Hi Kumar,
Thanks for your inquiry. You can use the following code to copy formatting of one cell to other cells.
Document doc = new Document("C:\\Temp\\test_old.doc");
Table tab = (Table)doc.getChildNodes(NodeType.TABLE, true).get(0);
// Cell whose formatting you want to apply to other cells
Cell targetCell = tab.getFirstRow().getFirstCell();
// Cell to which you want to apply formatting
Cell cell1 = tab.getRows().get(1).getCells().get(0);
Cell cell2 = tab.getRows().get(2).getCells().get(0);
copyFormatting(targetCell.getCellFormat(), cell1.getCellFormat());
copyFormatting(targetCell.getCellFormat(), cell2.getCellFormat());
doc.save("C:\\Temp\\output.doc");
public static void copyFormatting ( Object source , Object dest ) throws Exception
{
if ( source . getClass () != dest . getClass ())
throw new Exception ("All objects must be of the same type");
Method methodlist[] = source.getClass().getDeclaredMethods();
// Iterate through each property in the source object.
for ( Method prop: methodlist )
{
// Continue processing only if the method starts with get.
if ( !prop . getName (). startsWith ("get"))
continue;
// Skip indexed access items. Skip setting the internals of a style as these should not be changed.
if (prop.getName() == "getItem" || prop.getName() == "getStyle" ||
prop.getName() == "getStyleName" || prop.getName() == "getStyleIdentifier")
continue;
Object value;
// Wrap this call as it can throw an exception. Skip if thrown
try
{
// Get value by invoking getter method.
value = prop . invoke ( source );
}
catch ( Exception e )
{
continue;
}
// Get the corresponding setter method.
Method setter = null;
try
{
setter = source.getClass().getDeclaredMethod(prop.getName().replace("get", "set"), prop.getReturnType());
}
catch ( Exception e )
{
// do nothing if throws.
}
// Skip if value can not be retrieved.
if ( value != null)
{
// If this property returns a class which belongs to the
if (prop.getReturnType().getPackage() != null && prop.getReturnType().getPackage().getName().equals("com.aspose.words"))
{
// Recurse into this class.
copyFormatting ( prop . invoke ( source ), prop . invoke ( dest ));
}
else if ( setter != null)
{
// If we can write to this property then copy the value across.
setter . invoke ( dest , prop . invoke ( source ));
}
}
}
}
Best regards,
Hi Awais,
Went with cell.getPreviousSibling() and then copy border properties for horizontal merge. Similarly, used row.getPreviousSibling for vertical merge.
Thanks for your help.
Thanks,
Kumar
Hi Kumar,
It’s great you were able to find what you were looking for. Please let us know any time you have any further queries.
Best regards,