Skip to content

Commit ca10604

Browse files
authored
Merge pull request #18 from fahadadeel/main
Add New Features for GetColumnHeading and GetHiddenSheets Methods
2 parents 8c9f270 + e653814 commit ca10604

File tree

2 files changed

+156
-0
lines changed

2 files changed

+156
-0
lines changed

FileFormat.Cells/Workbook.cs

+47
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,53 @@ public void SetSheetVisibility(string sheetName, SheetVisibility visibility)
404404
throw new ArgumentException($"Sheet '{sheetName}' not found in the workbook.");
405405
}
406406
}
407+
408+
/// <summary>
409+
/// Retrieves a list of hidden or very hidden sheets from the workbook.
410+
/// </summary>
411+
/// <returns>A list of tuples where each tuple contains the sheet ID and sheet name for hidden sheets.</returns>
412+
/// <exception cref="InvalidOperationException">Thrown when the workbook part is not initialized.</exception>
413+
/// <exception cref="ArgumentNullException">Thrown when a sheet's ID or Name is null.</exception>
414+
public List<Tuple<string, string>> GetHiddenSheets()
415+
{
416+
if (workbookpart is null)
417+
throw new InvalidOperationException("WorkbookPart is not initialized.");
418+
419+
List<Tuple<string, string>> returnVal = new List<Tuple<string, string>>();
420+
421+
// Retrieves all sheets in the workbook.
422+
// Reference: DocumentFormat.OpenXml.Spreadsheet.Sheet
423+
var sheets = workbookpart.Workbook.Descendants<Sheet>();
424+
425+
// Look for sheets where there is a State attribute defined,
426+
// where the State has a value,
427+
// and where the value is either Hidden or VeryHidden.
428+
// Reference: DocumentFormat.OpenXml.Spreadsheet.SheetStateValues
429+
var hiddenSheets = sheets.Where(item => item.State is not null &&
430+
item.State.HasValue &&
431+
(item.State.Value == SheetStateValues.Hidden ||
432+
item.State.Value == SheetStateValues.VeryHidden));
433+
434+
// Populate the return list with the sheet ID and name as tuples.
435+
foreach (var sheet in hiddenSheets)
436+
{
437+
// Check if sheet ID or Name is null
438+
if (sheet.Id is null)
439+
throw new ArgumentNullException(nameof(sheet.Id), "Sheet ID cannot be null.");
440+
441+
if (sheet.Name is null)
442+
throw new ArgumentNullException(nameof(sheet.Name), "Sheet Name cannot be null.");
443+
444+
returnVal.Add(new Tuple<string, string>(
445+
sheet.Id, // The ID of the sheet, typically used to reference the sheet in the workbook.
446+
sheet.Name // The name of the sheet as displayed in the workbook.
447+
));
448+
}
449+
450+
return returnVal;
451+
}
452+
453+
407454

408455

409456
/// <summary>

FileFormat.Cells/Worksheet.cs

+109
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)