1+ using System . Text ;
2+ using Syncfusion . DocIO ;
3+ using Syncfusion . DocIO . DLS ;
4+ using Syncfusion . XlsIO ;
5+
6+ class Program
7+ {
8+ static void Main ( string [ ] args )
9+ {
10+ // Load existing word document
11+ using ( FileStream inputfileStream = new FileStream ( Path . GetFullPath ( @"../../../Data/Input.docx" ) , FileMode . Open ) )
12+ {
13+ using ( WordDocument document = new WordDocument ( inputfileStream , FormatType . Automatic ) )
14+ {
15+ using ( ExcelEngine engine = new ExcelEngine ( ) )
16+ {
17+ IApplication app = engine . Excel ;
18+ app . DefaultVersion = ExcelVersion . Excel2016 ;
19+
20+ // Create one sheet to start with; we’ll add sheets as we find more tables.
21+ IWorkbook workbook = app . Workbooks . Create ( 1 ) ;
22+ int sheetIndex = 0 ;
23+ int tableNumber = 0 ;
24+
25+ // Get table entities in word document
26+ List < Entity > entities = document . FindAllItemsByProperty ( EntityType . Table , null , null ) ;
27+
28+ foreach ( Entity entity in entities )
29+ {
30+ WTable wTable = ( WTable ) entity ;
31+
32+ if ( sheetIndex >= workbook . Worksheets . Count )
33+ workbook . Worksheets . Create ( ) ;
34+
35+ IWorksheet worksheet = workbook . Worksheets [ sheetIndex ++ ] ;
36+ worksheet . Name = $ "Table{ ++ tableNumber } ";
37+
38+ // Export with merges starting
39+ ExportWordTableToExcelMerged ( wTable , worksheet ) ;
40+
41+ // Formatting
42+ worksheet . UsedRange . AutofitRows ( ) ;
43+ worksheet . UsedRange . AutofitColumns ( ) ;
44+ }
45+ using ( FileStream outputStream = new FileStream ( Path . GetFullPath ( @"../../../Output/Result.xlsx" ) , FileMode . Create ) )
46+ {
47+ workbook . SaveAs ( outputStream ) ;
48+ }
49+ workbook . Close ( ) ;
50+ }
51+ }
52+ }
53+ }
54+
55+ /// <summary>
56+ /// Writes a Word table to the worksheet, preserving horizontal and vertical merges.
57+ /// startRow/startCol are 1-based Excel coordinates where the table should be placed.
58+ /// </summary>
59+ static void ExportWordTableToExcelMerged ( IWTable table , IWorksheet worksheet )
60+ {
61+ for ( int r = 0 ; r < table . Rows . Count ; r ++ )
62+ {
63+ WTableRow wRow = ( WTableRow ) table . Rows [ r ] ;
64+
65+ // Map Word's logical grid to Excel columns using GridSpan
66+ int gridCol = 1 ;
67+
68+ for ( int i = 0 ; i < wRow . Cells . Count ; i ++ )
69+ {
70+ WTableCell wCell = wRow . Cells [ i ] ;
71+
72+ // Horizontal width in grid columns
73+ int hSpan = ( int ) wCell . GridSpan ;
74+
75+ // Merge flags
76+ CellMerge vFlag = wCell . CellFormat . VerticalMerge ; // None | Start | Continue
77+ CellMerge hFlag = wCell . CellFormat . HorizontalMerge ;
78+
79+ // Excel start cell for this Word cell
80+ int excelStartRowIndex = r + 1 ;
81+ int excelStartColIndex = gridCol ;
82+
83+ // Compute vertical span when this cell is the START of a vertical merge
84+ int vSpan = 1 ;
85+ if ( vFlag == CellMerge . Start )
86+ {
87+ // Count how many subsequent rows continue the merge at the same grid column
88+ for ( int nr = r + 1 ; nr < table . Rows . Count ; nr ++ )
89+ {
90+ WTableRow nextRow = ( WTableRow ) table . Rows [ nr ] ;
91+ WTableCell nextCell = GetCellAtGridColumn ( nextRow , excelStartColIndex ) ; // 1-based grid col
92+ if ( nextCell != null && nextCell . CellFormat . VerticalMerge == CellMerge . Continue )
93+ vSpan ++ ;
94+ else
95+ break ;
96+ }
97+ }
98+ if ( hFlag == CellMerge . Start )
99+ {
100+ for ( int nc = i + 1 ; nc < wRow . Cells . Count ; nc ++ )
101+ {
102+ WTableCell cell = wRow . Cells [ nc ] ;
103+ if ( cell != null && cell . CellFormat . HorizontalMerge == CellMerge . Continue )
104+ hSpan += cell . GridSpan ;
105+ else
106+ break ;
107+ }
108+ }
109+
110+ // Is Start or None of a merge region
111+ bool isNotContinuedCell =
112+ ( vFlag != CellMerge . Continue ) &&
113+ ( hFlag != CellMerge . Continue ) ;
114+
115+ if ( isNotContinuedCell )
116+ {
117+ int vMergeEndIndex = excelStartRowIndex + vSpan - 1 ;
118+ int hMergeEndColIndex = excelStartColIndex + hSpan - 1 ;
119+
120+ // Merge in Excel if region spans multiple cells
121+ if ( vMergeEndIndex > excelStartRowIndex || hMergeEndColIndex > excelStartColIndex )
122+ worksheet . Range [ excelStartRowIndex , excelStartColIndex , vMergeEndIndex , hMergeEndColIndex ] . Merge ( ) ;
123+
124+ // Write the visible text to the top-left Excel cell
125+ IRange range = worksheet . Range [ excelStartRowIndex , excelStartColIndex ] ;
126+ range . Text = BuildCellText ( wCell ) ;
127+
128+ // Format styling
129+ range . CellStyle . HorizontalAlignment = ExcelHAlign . HAlignCenter ;
130+ range . CellStyle . VerticalAlignment = ExcelVAlign . VAlignCenter ;
131+
132+ worksheet . Range [ excelStartRowIndex , excelStartColIndex , vMergeEndIndex , hMergeEndColIndex ] . CellStyle . Borders [ ExcelBordersIndex . EdgeLeft ] . LineStyle = ExcelLineStyle . Thin ;
133+ worksheet . Range [ excelStartRowIndex , excelStartColIndex , vMergeEndIndex , hMergeEndColIndex ] . CellStyle . Borders [ ExcelBordersIndex . EdgeRight ] . LineStyle = ExcelLineStyle . Thin ;
134+ worksheet . Range [ excelStartRowIndex , excelStartColIndex , vMergeEndIndex , hMergeEndColIndex ] . CellStyle . Borders [ ExcelBordersIndex . EdgeTop ] . LineStyle = ExcelLineStyle . Thin ;
135+ worksheet . Range [ excelStartRowIndex , excelStartColIndex , vMergeEndIndex , hMergeEndColIndex ] . CellStyle . Borders [ ExcelBordersIndex . EdgeBottom ] . LineStyle = ExcelLineStyle . Thin ;
136+
137+ }
138+
139+ // Advance Excel column cursor by the horizontal span of this Word cell
140+ gridCol += hSpan ;
141+ }
142+ }
143+ }
144+
145+ /// <summary>
146+ /// Returns the WTableCell occupying the given 1-based "grid column" in this row,
147+ /// taking each cell's GridSpan into account.
148+ /// </summary>
149+ static WTableCell GetCellAtGridColumn ( WTableRow row , int gridColumn )
150+ {
151+ int cursor = 1 ; // 1-based grid column within the table
152+ foreach ( WTableCell c in row . Cells )
153+ {
154+ int span = ( int ) c . GridSpan ;
155+ int start = cursor ;
156+ int end = cursor + span - 1 ;
157+ if ( gridColumn >= start && gridColumn <= end )
158+ return c ;
159+ cursor += span ;
160+ }
161+ return null ;
162+ }
163+
164+ /// <summary>
165+ /// Concatenate all paragraph texts in a Word cell (one per line).
166+ /// </summary>
167+ static string BuildCellText ( WTableCell cell )
168+ {
169+ StringBuilder sb = new StringBuilder ( ) ;
170+ for ( int p = 0 ; p < cell . Paragraphs . Count ; p ++ )
171+ {
172+ WParagraph para = cell . Paragraphs [ p ] ;
173+ string text = para . Text ? . TrimEnd ( ) ;
174+ if ( ! string . IsNullOrEmpty ( text ) )
175+ {
176+ if ( sb . Length > 0 ) sb . AppendLine ( ) ;
177+ sb . Append ( text ) ;
178+ }
179+ }
180+ return sb . ToString ( ) ;
181+ }
182+ }
0 commit comments