diff --git a/Examples/ApiExamples/ApiExamples/ExTable.cs b/Examples/ApiExamples/ApiExamples/ExTable.cs index 66b8d3be..56ab17bc 100644 --- a/Examples/ApiExamples/ApiExamples/ExTable.cs +++ b/Examples/ApiExamples/ApiExamples/ExTable.cs @@ -1696,5 +1696,201 @@ public void GetTextFromCells() } //ExEnd } + + [Test] + public void ConvertWithParagraphMark() + { + Document doc = new Document(MyDir + "Nested tables.docx"); + Table table = (Table)doc.GetChild(NodeType.Table, 0, true); + + // Replace the table with the new paragraph + ConvertTable(table); + + table.Remove(); + + doc.Save(ArtifactsDir + "output.docx"); + } + + /// + /// Recursively converts nested tables within a given table. + /// + /// The table to be converted. + private void ConvertTable(Table table) + { + Node currentNode = table; + foreach (Row row in table.Rows) + { + foreach (Cell cell in row.Cells) + { + // Get all nested tables within the current cell. + NodeCollection nestedTables = cell.GetChildNodes(NodeType.Table, true); + if (nestedTables.Count != 0) + foreach (Table nestedTable in nestedTables) + ConvertTable(nestedTable); + + // Get the text content of the cell and trim any whitespace. + var cellText = cell.GetText().Trim(); + if (cellText == string.Empty) + break; + + foreach (Paragraph cellPara in cell.Paragraphs) + currentNode = table.ParentNode.InsertAfter(cellPara.Clone(true), currentNode); + } + } + } + + [Test] + public void ConvertWith() + { + Document doc = new Document(MyDir + "Nested tables.docx"); + Table table = (Table)doc.GetChild(NodeType.Table, 0, true); + + // Convert table to text with specified separator. + ConvertWith(ControlChar.Tab, table); + // Remove table after convertion. + table.Remove(); + + doc.Save(ArtifactsDir + "Table.ConvertWith.docx"); + } + + /// + /// Converts the content of a table into a series of paragraphs, separated by a specified separator. + /// + /// The string used to separate the content of each cell. + /// The table to be converted. + private void ConvertWith(string separator, Table table) + { + Document doc = (Document)table.Document; + Node currentPara = table.NextSibling; + foreach (Row row in table.Rows) + { + double tabStopWidth = 0; + // By default MS Word adds 1.5 line spacing bitween paragraphs. + ((Paragraph)currentPara).ParagraphFormat.LineSpacing = 18; + foreach (Cell cell in row.Cells) + { + NodeCollection nestedTables = cell.GetChildNodes(NodeType.Table, true); + // If there are nested tables, process each one. + if (nestedTables.Count != 0) + foreach (Table nestedTable in nestedTables) + ConvertWith(separator, nestedTable); + + ParagraphCollection paragraphs = cell.Paragraphs; + foreach (Paragraph paragraph in paragraphs) + { + // If there's more than one paragraph and it's not the first, clone and insert it after the current paragraph. + if (paragraphs.Count > 1 && !paragraph.Equals(cell.FirstParagraph)) + { + Node node = currentPara.ParentNode.InsertAfter(paragraph.Clone(true), currentPara); + currentPara = node; + } + else if (currentPara.NodeType == NodeType.Paragraph) + { + // If the current cell is not the first cell, append a separator. + if (!cell.IsFirstCell) + { + ((Paragraph)currentPara).AppendChild(new Run(doc, separator)); + // If the separator is a tab, calculate the tab stop position based on the width of the previous cell. + if (separator == ControlChar.Tab) + { + var previousCell = cell.PreviousCell; + if (previousCell != null) + tabStopWidth += previousCell.CellFormat.Width; + + // Add a tab stop at the calculated position. + TabStop tabStop = new TabStop(tabStopWidth, TabAlignment.Left, TabLeader.None); + ((Paragraph)currentPara).ParagraphFormat.TabStops.Add(tabStop); + } + } + + // Clone and append all child nodes of the paragraph to the current paragraph. + var childNodes = paragraph.GetChildNodes(NodeType.Any, true); + if (childNodes.Count > 0) + foreach (Node node in childNodes) + ((Paragraph)currentPara).AppendChild(node.Clone(true)); + } + } + } + + currentPara = currentPara.ParentNode.InsertAfter(new Paragraph(doc), currentPara); + } + } + + [Test] + public void GetColSpanRowSpan() + { + Document doc = new Document(MyDir + "merged.docx"); + + var table = (Table)doc.GetChild(NodeType.Table, 0, true); + // Convert cells with merged columns into a format that can be easily manipulated. + table.ConvertToHorizontallyMergedCells(); + + foreach (Row row in table.Rows) + { + var cell = row.FirstCell; + + while (cell != null) + { + var rowIndex = table.IndexOf(row); + var cellIndex = cell.ParentRow.IndexOf(cell); + + var rowSpan = 1; + var colSpan = 1; + + // Check if the current cell is the start of a vertically merged set of cells. + if (cell.CellFormat.VerticalMerge == CellMerge.First) + rowSpan = CalculateRowSpan(table, rowIndex, cellIndex); + + // Check if the current cell is the start of a horizontally merged set of cells. + if (cell.CellFormat.HorizontalMerge == CellMerge.First) + cell = CalculateColSpan(cell, out colSpan); + else + cell = cell.NextCell; + + Console.WriteLine($"RowIndex = {rowIndex}\t ColSpan = {colSpan}\t RowSpan = {rowSpan}"); + } + } + } + + /// + /// Calculates the row span for a cell in a table. + /// + /// The table containing the cell. + /// The index of the row containing the cell. + /// The index of the cell within the row. + /// The number of rows spanned by the cell. + private int CalculateRowSpan(Table table, int rowIndex, int cellIndex) + { + var rowSpan = 1; + for (int i = rowIndex; i < table.Rows.Count; i++) + { + var currentRow = table.Rows[i + 1]; + var currentCell = currentRow.Cells[cellIndex]; + if (currentRow == null || currentCell.CellFormat.VerticalMerge != CellMerge.Previous) + break; + + rowSpan++; + } + return rowSpan; + } + + /// + /// Calculates the column span of a cell based on its horizontal merge settings. + /// + /// The cell for which to calculate the column span. + /// The resulting column span value. + /// The next cell in the sequence after calculating the column span. + private Cell CalculateColSpan(Cell cell, out int colSpan) + { + colSpan = 1; + + cell = cell.NextCell; + while (cell != null && cell.CellFormat.HorizontalMerge == CellMerge.Previous) + { + colSpan++; + cell = cell.NextCell; + } + return cell; + } } } \ No newline at end of file