@@ -1535,6 +1535,115 @@ public void InsertColumns(string startColumn, int numberOfColumns)
15351535 _worksheetPart . Worksheet . Save ( ) ;
15361536 }
15371537
1538+ /// <summary>
1539+ /// Gets the column heading for a specified cell in the worksheet.
1540+ /// </summary>
1541+ /// <param name="cellName">The name of the cell (e.g., "A1").</param>
1542+ /// <returns>The text of the column heading, or null if the column does not exist.</returns>
1543+ /// <exception cref="ArgumentException">Thrown when the cellName is null or empty.</exception>
1544+ /// <exception cref="InvalidOperationException">Thrown when the WorkbookPart is not found, the sheet is not found,
1545+ /// the column name is invalid, no header cell is found, or the SharedStringTablePart is missing.</exception>
1546+ /// <exception cref="IndexOutOfRangeException">Thrown when the shared string index is out of range.</exception>
1547+ public string ? GetColumnHeadingNew ( string cellName )
1548+ {
1549+ if ( string . IsNullOrEmpty ( cellName ) )
1550+ throw new ArgumentException ( "Cell name cannot be null or empty." , nameof ( cellName ) ) ;
1551+
1552+ var workbookPart = _worksheetPart . GetParentParts ( ) . OfType < WorkbookPart > ( ) . FirstOrDefault ( ) ;
1553+ if ( workbookPart == null )
1554+ throw new InvalidOperationException ( "No WorkbookPart found." ) ;
1555+
1556+ var sheets = workbookPart . Workbook . Descendants < DocumentFormat . OpenXml . Spreadsheet . Sheet > ( ) ;
1557+ var sheet = sheets . FirstOrDefault ( s => workbookPart . GetPartById ( s . Id ) == _worksheetPart ) ;
1558+
1559+ if ( sheet == null )
1560+ throw new InvalidOperationException ( "No matching sheet found for the provided WorksheetPart." ) ;
1561+
1562+ WorksheetPart worksheetPart = _worksheetPart ;
1563+
1564+ // Get the column name for the specified cell.
1565+ string columnName = GetColumnName ( cellName ) ;
1566+
1567+ if ( string . IsNullOrEmpty ( columnName ) )
1568+ throw new InvalidOperationException ( "Unable to determine the column name from the provided cell name." ) ;
1569+
1570+ // Get the cells in the specified column and order them by row.
1571+ IEnumerable < DocumentFormat . OpenXml . Spreadsheet . Cell > cells = worksheetPart . Worksheet . Descendants < DocumentFormat . OpenXml . Spreadsheet . Cell > ( )
1572+ . Where ( c => string . Compare ( GetColumnName ( c . CellReference ? . Value ) , columnName , true ) == 0 )
1573+ . OrderBy ( r => GetRowIndexN ( r . CellReference ) ?? 0 ) ;
1574+
1575+ if ( ! cells . Any ( ) )
1576+ {
1577+ // The specified column does not exist.
1578+ return null ;
1579+ }
1580+
1581+ // Get the first cell in the column.
1582+ DocumentFormat . OpenXml . Spreadsheet . Cell headCell = cells . First ( ) ;
1583+
1584+ if ( headCell == null )
1585+ throw new InvalidOperationException ( "No header cell found in the specified column." ) ;
1586+
1587+ // If the content of the first cell is stored as a shared string, get the text of the first cell
1588+ // from the SharedStringTablePart and return it. Otherwise, return the string value of the cell.
1589+ if ( headCell . DataType != null && headCell . DataType . Value == CellValues . SharedString && int . TryParse ( headCell . CellValue ? . Text , out int index ) )
1590+ {
1591+ var sharedStringPart = workbookPart . GetPartsOfType < SharedStringTablePart > ( ) . FirstOrDefault ( ) ;
1592+ if ( sharedStringPart == null )
1593+ throw new InvalidOperationException ( "No SharedStringTablePart found." ) ;
1594+
1595+ var items = sharedStringPart . SharedStringTable . Elements < SharedStringItem > ( ) . ToArray ( ) ;
1596+ if ( index < 0 || index >= items . Length )
1597+ throw new IndexOutOfRangeException ( "Shared string index is out of range." ) ;
1598+
1599+ return items [ index ] . InnerText ;
1600+ }
1601+ else
1602+ {
1603+ return headCell . CellValue ? . Text ;
1604+ }
1605+ }
1606+
1607+
1608+ /// <summary>
1609+ /// Gets the row index from the specified cell name.
1610+ /// </summary>
1611+ /// <param name="cellName">The cell name in A1 notation (e.g., "A1").</param>
1612+ /// <returns>The row index as a nullable unsigned integer, or null if the cell name is invalid.</returns>
1613+ /// <exception cref="FormatException">Thrown when the row index portion of the cell name cannot be parsed.</exception>
1614+ private uint ? GetRowIndexN ( string ? cellName )
1615+ {
1616+ if ( cellName is null )
1617+ {
1618+ return null ;
1619+ }
1620+
1621+ // Create a regular expression to match the row index portion the cell name.
1622+ Regex regex = new Regex ( @"\d+" ) ;
1623+ Match match = regex . Match ( cellName ) ;
1624+
1625+ return uint . Parse ( match . Value ) ;
1626+ }
1627+
1628+ /// <summary>
1629+ /// Given a cell name, parses the specified cell to get the column name.
1630+ /// </summary>
1631+ /// <param name="cellName">The cell name in A1 notation (e.g., "A1").</param>
1632+ /// <returns>The column name as a string, or an empty string if the cell name is invalid.</returns>
1633+ private string GetColumnName ( string ? cellName )
1634+ {
1635+ if ( cellName is null )
1636+ {
1637+ return string . Empty ;
1638+ }
1639+
1640+ // Create a regular expression to match the column name portion of the cell name.
1641+ Regex regex = new Regex ( "[A-Za-z]+" ) ;
1642+ Match match = regex . Match ( cellName ) ;
1643+
1644+ return match . Value ;
1645+ }
1646+
15381647 private static string IncrementColumnReference ( string reference , int columnCount )
15391648 {
15401649 var regex = new System . Text . RegularExpressions . Regex ( "([A-Za-z]+)(\\ d+)" ) ;
0 commit comments