Can you please be more specific about what do you want to achieve, the second file that you posted have a complete different format for the table section (in this case the document have two columns).
@Nachti this case is wide more complex than the first one, I created a piece of code based in the previous solution:
Document doc = new Document(@"C:\\Temp\\input.docx");
Document tempDoc = (Document)doc.Clone(true);
Document tempDocNoCol = (Document)tempDoc.Clone(true);
// Clear multiple column to use as reference
foreach (Section section in tempDocNoCol.Sections)
{
section.PageSetup.TextColumns.SetCount(1);
}
int sectionIndex = 0;
foreach (Section section in tempDoc.Sections)
{
NodeCollection tables = section.GetChildNodes(NodeType.Table, true);
NodeCollection tablesNoCol = tempDocNoCol.Sections[sectionIndex++].GetChildNodes(NodeType.Table, true);
// Amount of columns in the page
var textColCount = section.PageSetup.TextColumns.Count;
for (int i = 0; i < tables.Count; i++)
{
Table table = (Table)tables[i];
ArrayList splitIndices = new ArrayList();
if (tablesNoCol != null && tablesNoCol.Count > i)
{
Table tableNoCol = (Table)tablesNoCol[i];
int rowCount = tableNoCol.Rows.Count;
// Evaluate if the current section contains more than 1 text column
if (textColCount > 1)
{
LayoutCollector collector = new LayoutCollector(tempDocNoCol);
int startPage = collector.GetStartPageIndex(tableNoCol.FirstRow.FirstCell.FirstParagraph);
int endPage = collector.GetEndPageIndex(tableNoCol.LastRow.LastCell.LastParagraph);
if (endPage > startPage)
{
// Check how many rows fit in the first page of the table
int rowsInFirstPage = 0;
for (int x = 0; rowsInFirstPage == 0 && x < rowCount; x++)
{
Row row = tableNoCol.Rows[x];
int endRow = collector.GetEndPageIndex(row.LastCell.LastParagraph);
if (endRow > startPage)
{
rowsInFirstPage = x;
}
}
if(rowsInFirstPage == 0)
{
rowsInFirstPage = rowCount;
}
splitIndices.Add(rowsInFirstPage < rowCount ? rowsInFirstPage : rowCount);
// Set indices to split the table in the first page
for (int x = 2; x <= textColCount; x++)
{
var rowIndex = rowsInFirstPage * x;
// Removing 2 to compensate the extra space generated for the line break in between the tables
splitIndices.Add(rowIndex < (rowCount - 2) ? rowIndex - 2 : rowCount);
}
// Check if the table ends in he first page, if not that implies that all the rest of the table should be placed in a new page
var totalRowsInFirstPage = rowsInFirstPage * textColCount - 2 * textColCount;
if (totalRowsInFirstPage < rowCount)
{
// Need to check how many rows fit in an empty page
Document temp = (Document)tempDocNoCol.Clone(true);
temp.FirstSection.Body.RemoveAllChildren();
temp.FirstSection.Body.AppendChild(temp.ImportNode(tableNoCol, true));
LayoutCollector tempCollector = new LayoutCollector(temp);
Table tempTable = temp.FirstSection.Body.Tables[0];
startPage = tempCollector.GetStartPageIndex(tempTable.FirstRow.FirstCell.FirstParagraph);
endPage = tempCollector.GetEndPageIndex(tempTable.LastRow.LastCell.LastParagraph);
if (endPage > startPage)
{
// Check how many rows enter in a single page
int rowsPerPage = 0;
for (int x = 0; rowsPerPage == 0 && x < rowCount; x++)
{
Row row = tempTable.Rows[x];
int endRow = tempCollector.GetEndPageIndex(row.LastCell.LastParagraph);
if (endRow > startPage)
{
rowsPerPage = x;
}
}
// Insert the rest of the indices
if (rowsPerPage == 0)
{
rowsPerPage = rowCount;
}
var remainingRows = rowCount - totalRowsInFirstPage;
var rowIndex = totalRowsInFirstPage + rowsPerPage - 2;
splitIndices.Add(rowIndex > remainingRows ? remainingRows : rowIndex);
while (rowIndex < remainingRows)
{
rowIndex += rowsPerPage - 2;
splitIndices.Add(rowIndex > remainingRows ? remainingRows : rowIndex);
}
}
else // This mean that the table fit in a single page
{
splitIndices.Add(rowCount);
}
}
for (int x = splitIndices.Count - 1; x > 0; x--)
{
SplitTable(table, (int)splitIndices[x - 1], (int)splitIndices[x]);
}
for (int x = (int)splitIndices[0]; x < rowCount; x++)
{
table.LastRow.Remove();
}
}
}
}
}
}
tempDoc.Save(@"C:\\Temp\\output.docx");
static Table SplitTable(Table table, int startIndex, int endIndex)
{
Table newTable = (Table)table.Clone(true);
table.ParentNode.InsertAfter(newTable, table);
for (int i = 0; i < startIndex; i++)
{
newTable.FirstRow.Remove();
}
for (int i = endIndex; i < table.Rows.Count; i++)
{
newTable.LastRow.Remove();
}
if (table.FirstRow.RowFormat.HeadingFormat)
{
Row headingRow = (Row)table.FirstRow.Clone(true);
newTable.InsertBefore(headingRow, newTable.FirstRow);
}
Paragraph separator = new Paragraph(table.Document);
table.ParentNode.InsertAfter(separator, table);
return newTable;
}
@Nachti that’s not happening to me for the document that you posted I’m getting the following result: output.docx (15.1 KB)
Can you please post a print of the error?
@Nachti Please try using the following code. It uses LayoutCollector and LayoutEnumerator to determine where the table need to be split. One contiotion is the page index change and another X coordinate of the row change (column break):
Document doc = new Document(@"C:\Temp\in.docx");
LayoutCollector collector = new LayoutCollector(doc);
LayoutEnumerator enumerator = new LayoutEnumerator(doc);
NodeCollection tables = doc.GetChildNodes(NodeType.Table, true);
foreach (Table t in tables)
{
// Process only top level table in the main document's body.
if (t.ParentNode.NodeType != NodeType.Body)
continue;
Table table = t;
while (table != null)
{
table = SplitTalbeTextColumns(table, collector, enumerator);
if (table != null)
{
// Do not update layout if it is not required.
collector.Clear();
doc.UpdatePageLayout();
}
}
}
doc.Save(@"C:\Temp\out.docx");
private static Table SplitTalbeTextColumns(Table table, LayoutCollector collector, LayoutEnumerator enumerator)
{
int startPageIndex = collector.GetStartPageIndex(table.FirstRow);
enumerator.Current = collector.GetEntity(table.FirstRow.FirstCell.FirstParagraph);
while (enumerator.Type != LayoutEntityType.Row)
enumerator.MoveParent();
double startRowX = enumerator.Rectangle.Left;
int breakIndex = -1;
int firstDataRowIndex = -1;
// Determine index of row where page breaks. And index of the first data row.
for (int i = 1; i < table.Rows.Count; i++)
{
Row r = table.Rows[i];
if (!r.RowFormat.HeadingFormat && firstDataRowIndex < 0)
firstDataRowIndex = i;
int rowPageIndex = collector.GetEndPageIndex(r);
if (rowPageIndex > startPageIndex)
{
breakIndex = i;
break;
}
// Determine X coordinate of the row.
enumerator.Current = collector.GetEntity(r.FirstCell.FirstParagraph);
while (enumerator.Type != LayoutEntityType.Row)
enumerator.MoveParent();
double currentRowX = enumerator.Rectangle.Left;
if (startRowX != currentRowX)
{
breakIndex = i;
break;
}
}
if (breakIndex > 0)
{
Table clone = (Table)table.Clone(true);
// Insert a cloned table after the main table.
Paragraph para = new Paragraph(table.Document);
para.AppendChild(new Run(table.Document, ControlChar.ColumnBreak + "Continuation of the table"));
table.ParentNode.InsertAfter(para, table);
para.ParentNode.InsertAfter(clone, para);
// Remove content after the breaking row from the main table.
while (table.Rows.Count > breakIndex)
table.LastRow.Remove();
// Remove rows before the breaking row from the clonned table.
for (int i = 1; i < breakIndex; i++)
clone.Rows.RemoveAt(firstDataRowIndex);
return clone;
}
return null;
}
Sets consent for sending user data to Google for online advertising purposes.
Sets consent for personalized advertising.
Cookie Notice
To provide you with the best experience, we use cookies for personalization, analytics, and ads. By using our site, you agree to our cookie policy.
More info
Enables storage, such as cookies, related to analytics.
Enables storage, such as cookies, related to advertising.
Sets consent for sending user data to Google for online advertising purposes.
Sets consent for personalized advertising.
Cookie Notice
To provide you with the best experience, we use cookies for personalization, analytics, and ads. By using our site, you agree to our cookie policy.
More info
Enables storage, such as cookies, related to analytics.
Enables storage, such as cookies, related to advertising.
Sets consent for sending user data to Google for online advertising purposes.