Skip to content

Commit afbcd15

Browse files
committed
.
1 parent 87d0878 commit afbcd15

7 files changed

+110
-69
lines changed

readme.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,12 @@ public Task VerifySpreadsheetDocument()
9898
<a id='snippet-Samples.VerifyExcel.verified.csv'></a>
9999
```csv
100100
0,First Name,Last Name,Gender,Country,Date,Age,Id,Formula
101-
1,Dulce,Abril,Female,United States,43023,32,1562,G2+H21594
102-
2,Mara,Hashimoto,Female,Great Britain,42598,25,1582,1607
103-
3,Philip,Gent,Male,France,42145,36,2587,2623
104-
4,Kathleen,Hanner,Female,United States,43023,25,3549,3574
105-
5,Nereida,Magwood,Female,United States,42598,58,2468,2526
106-
6,Gaston,Brumm,Male,United States,42145,24,2554,2578
101+
1,Dulce,Abril,Female,United States,2017-10-15 00:00:00,32,1562,G2+H21594
102+
2,Mara,Hashimoto,Female,Great Britain,2016-08-16 00:00:00,25,1582,1607
103+
3,Philip,Gent,Male,France,2015-05-21 00:00:00,36,2587,2623
104+
4,Kathleen,Hanner,Female,United States,2017-10-15 00:00:00,25,3549,3574
105+
5,Nereida,Magwood,Female,United States,2016-08-16 00:00:00,58,2468,2526
106+
6,Gaston,Brumm,Male,United States,2015-05-21 00:00:00,24,2554,2578
107107
```
108108
<sup><a href='/src/Tests/Samples.VerifyExcel.verified.csv#L1-L7' title='Snippet source file'>snippet source</a> | <a href='#snippet-Samples.VerifyExcel.verified.csv' title='Start of snippet'>anchor</a></sup>
109109
<!-- endSnippet -->

src/Directory.Packages.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313
<PackageVersion Include="ProjectDefaults" Version="1.0.158" />
1414
<PackageVersion Include="Sylvan.Data.Csv" Version="1.4.2" />
1515
<PackageVersion Include="Sylvan.Data.Excel" Version="0.4.30" />
16-
<PackageVersion Include="Verify" Version="30.13.0" />
16+
<PackageVersion Include="Verify" Version="30.15.0" />
1717
<PackageVersion Include="Verify.DiffPlex" Version="3.1.2" />
18-
<PackageVersion Include="Verify.NUnit" Version="30.13.0" />
18+
<PackageVersion Include="Verify.NUnit" Version="30.15.0" />
1919
<PackageVersion Include="Microsoft.Sbom.Targets" Version="4.1.2" />
2020
</ItemGroup>
2121
</Project>
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
0,First Name,Last Name,Gender,Country,Date,Age,Id,Formula
2-
1,Dulce,Abril,Female,United States,43023,32,1562,G2+H21594
3-
2,Mara,Hashimoto,Female,Great Britain,42598,25,1582,1607
4-
3,Philip,Gent,Male,France,42145,36,2587,2623
5-
4,Kathleen,Hanner,Female,United States,43023,25,3549,3574
6-
5,Nereida,Magwood,Female,United States,42598,58,2468,2526
7-
6,Gaston,Brumm,Male,United States,42145,24,2554,2578
2+
1,Dulce,Abril,Female,United States,2017-10-15,32,1562,G2+H21594
3+
2,Mara,Hashimoto,Female,Great Britain,2016-08-16,25,1582,1607
4+
3,Philip,Gent,Male,France,2015-05-21,36,2587,2623
5+
4,Kathleen,Hanner,Female,United States,2017-10-15,25,3549,3574
6+
5,Nereida,Magwood,Female,United States,2016-08-16,58,2468,2526
7+
6,Gaston,Brumm,Male,United States,2015-05-21,24,2554,2578
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
0,First Name,Last Name,Gender,Country,Date,Age,Id,Formula
2-
1,Dulce,Abril,Female,United States,43023,32,1562,G2+H21594
3-
2,Mara,Hashimoto,Female,Great Britain,42598,25,1582,1607
4-
3,Philip,Gent,Male,France,42145,36,2587,2623
5-
4,Kathleen,Hanner,Female,United States,43023,25,3549,3574
6-
5,Nereida,Magwood,Female,United States,42598,58,2468,2526
7-
6,Gaston,Brumm,Male,United States,42145,24,2554,2578
2+
1,Dulce,Abril,Female,United States,2017-10-15,32,1562,G2+H21594
3+
2,Mara,Hashimoto,Female,Great Britain,2016-08-16,25,1582,1607
4+
3,Philip,Gent,Male,France,2015-05-21,36,2587,2623
5+
4,Kathleen,Hanner,Female,United States,2017-10-15,25,3549,3574
6+
5,Nereida,Magwood,Female,United States,2016-08-16,58,2468,2526
7+
6,Gaston,Brumm,Male,United States,2015-05-21,24,2554,2578
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
0,First Name,Last Name,Gender,Country,Date,Age,Id,Formula
2-
1,Dulce,Abril,Female,United States,43023,32,1562,G2+H21594
3-
2,Mara,Hashimoto,Female,Great Britain,42598,25,1582,1607
4-
3,Philip,Gent,Male,France,42145,36,2587,2623
5-
4,Kathleen,Hanner,Female,United States,43023,25,3549,3574
6-
5,Nereida,Magwood,Female,United States,42598,58,2468,2526
7-
6,Gaston,Brumm,Male,United States,42145,24,2554,2578
2+
1,Dulce,Abril,Female,United States,2017-10-15,32,1562,G2+H21594
3+
2,Mara,Hashimoto,Female,Great Britain,2016-08-16,25,1582,1607
4+
3,Philip,Gent,Male,France,2015-05-21,36,2587,2623
5+
4,Kathleen,Hanner,Female,United States,2017-10-15,25,3549,3574
6+
5,Nereida,Magwood,Female,United States,2016-08-16,58,2468,2526
7+
6,Gaston,Brumm,Male,United States,2015-05-21,24,2554,2578
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
0,First Name,Last Name,Gender,Country,Date,Age,Id,Formula
2-
1,Dulce,Abril,Female,United States,43023,32,1562,G2+H21594
3-
2,Mara,Hashimoto,Female,Great Britain,42598,25,1582,1607
4-
3,Philip,Gent,Male,France,42145,36,2587,2623
5-
4,Kathleen,Hanner,Female,United States,43023,25,3549,3574
6-
5,Nereida,Magwood,Female,United States,42598,58,2468,2526
7-
6,Gaston,Brumm,Male,United States,42145,24,2554,2578
2+
1,Dulce,Abril,Female,United States,2017-10-15,32,1562,G2+H21594
3+
2,Mara,Hashimoto,Female,Great Britain,2016-08-16,25,1582,1607
4+
3,Philip,Gent,Male,France,2015-05-21,36,2587,2623
5+
4,Kathleen,Hanner,Female,United States,2017-10-15,25,3549,3574
6+
5,Nereida,Magwood,Female,United States,2016-08-16,58,2468,2526
7+
6,Gaston,Brumm,Male,United States,2015-05-21,24,2554,2578

src/Verify.OpenXml/VerifyOpenXml.cs

Lines changed: 78 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ static ConversionResult Convert(Stream stream, IReadOnlyDictionary<string, objec
2626
static ConversionResult Convert(SpreadsheetDocument document, IReadOnlyDictionary<string, object> settings)
2727
{
2828
var sheets = Convert(document).ToList();
29+
2930
var info = new Info
3031
{
3132
SheetNames = sheets.Select(_ => _.Name!),
@@ -44,20 +45,21 @@ static ConversionResult Convert(SpreadsheetDocument document, IReadOnlyDictionar
4445
static IEnumerable<(StringBuilder Csv, string? Name)> Convert(SpreadsheetDocument document)
4546
{
4647
var workbookPart = document.WorkbookPart!;
48+
4749
foreach (var sheet in workbookPart.Workbook.Sheets!.Elements<Sheet>())
4850
{
49-
var worksheetPart = (WorksheetPart)workbookPart.GetPartById(sheet.Id!);
50-
51-
// Get shared string table for text values
52-
var sharedStringPart = workbookPart.SharedStringTablePart;
51+
var worksheetPart = (WorksheetPart) workbookPart.GetPartById(sheet.Id!);
5352

53+
var sharedStringItems = workbookPart.SharedStringTablePart?.SharedStringTable.Elements<SharedStringItem>().ToList();
5454
var builder = new StringBuilder();
5555

56-
foreach (var row in worksheetPart.Worksheet.Descendants<Row>().OrderBy(r => r.RowIndex))
56+
foreach (var row in worksheetPart.Worksheet
57+
.Descendants<Row>()
58+
.OrderBy(r => r.RowIndex))
5759
{
5860
foreach (var cell in row.Elements<Cell>())
5961
{
60-
var cellValue = GetCellValue(cell, sharedStringPart);
62+
var cellValue = GetCellValue(cell, workbookPart, sharedStringItems);
6163
builder.Append(EscapeCsvValue(cellValue));
6264
builder.Append(',');
6365
}
@@ -70,7 +72,7 @@ static ConversionResult Convert(SpreadsheetDocument document, IReadOnlyDictionar
7072
}
7173
}
7274

73-
private static string GetCellValue(Cell cell, SharedStringTablePart? sharedStringPart)
75+
static string GetCellValue(Cell cell, WorkbookPart workbookPart, List<SharedStringItem>? sharedStringItems)
7476
{
7577
var value = cell.InnerText;
7678

@@ -79,64 +81,103 @@ private static string GetCellValue(Cell cell, SharedStringTablePart? sharedStrin
7981
if (cell.DataType.Value == CellValues.SharedString)
8082
{
8183
// Handle shared strings
82-
if (sharedStringPart != null && int.TryParse(value, out var ssid))
84+
if (sharedStringItems != null &&
85+
int.TryParse(value, out var ssid))
8386
{
84-
return sharedStringPart.SharedStringTable.Elements<SharedStringItem>().ElementAt(ssid).InnerText;
87+
return sharedStringItems.ElementAt(ssid).InnerText;
8588
}
8689
}
8790
else if (cell.DataType.Value == CellValues.Boolean)
8891
{
89-
return value == "1" ? "TRUE" : "FALSE";
92+
return value == "1" ? "true" : "false";
9093
}
9194
else if (cell.DataType.Value == CellValues.Date)
9295
{
9396
if (double.TryParse(value, out var oaDate))
9497
{
95-
return DateTime.FromOADate(oaDate).ToString("yyyy-MM-dd");
98+
var date = DateTime.FromOADate(oaDate);
99+
return DateFormatter.Convert(date);
100+
}
101+
}
102+
}
103+
else if (!string.IsNullOrEmpty(value))
104+
{
105+
// Check if this is a date based on number format
106+
if (double.TryParse(value, out var numericValue))
107+
{
108+
if (IsCellDateFormatted(cell, workbookPart))
109+
{
110+
try
111+
{
112+
var date = DateTime.FromOADate(numericValue);
113+
return DateFormatter.Convert(date);
114+
}
115+
catch (ArgumentException)
116+
{
117+
// If conversion fails, return the original numeric value
118+
return value;
119+
}
96120
}
97121
}
98122
}
99123

100124
return value;
101125
}
102126

103-
static uint GetColumnIndex(string cellReference)
127+
static bool IsCellDateFormatted(Cell cell, WorkbookPart workbookPart)
104128
{
105-
if (string.IsNullOrEmpty(cellReference))
106-
return 0;
129+
if (cell.StyleIndex == null)
130+
{
131+
return false;
132+
}
107133

108-
// Extract column letters from cell reference (e.g., "A1" -> "A")
109-
var columnName = new string(cellReference.Where(char.IsLetter).ToArray());
110-
return GetColumnIndex2(columnName);
111-
}
134+
var stylesPart = workbookPart.WorkbookStylesPart;
135+
if (stylesPart?.Stylesheet.CellFormats == null)
136+
{
137+
return false;
138+
}
112139

113-
private static uint GetColumnIndex2(string columnName)
114-
{
115-
uint columnIndex = 0;
116-
for (var i = 0; i < columnName.Length; i++)
140+
var cellFormats = stylesPart.Stylesheet.CellFormats;
141+
var cellFormat = cellFormats.Elements<CellFormat>().ElementAtOrDefault((int) cell.StyleIndex.Value);
142+
143+
if (cellFormat?.NumberFormatId == null)
117144
{
118-
columnIndex = columnIndex * 26 + (uint)(columnName[i] - 'A' + 1);
145+
return false;
119146
}
120-
return columnIndex;
121-
}
122147

123-
private static string GetColumnName(uint columnIndex)
124-
{
125-
var columnName = "";
126-
while (columnIndex > 0)
148+
var numberFormatId = cellFormat.NumberFormatId.Value;
149+
150+
// Built-in date formats (14-22, 176-180, 181-183)
151+
if (numberFormatId is
152+
>= 14 and <= 22 or
153+
>= 176 and <= 180 or
154+
>= 181 and <= 183)
127155
{
128-
columnIndex--;
129-
columnName = (char)('A' + columnIndex % 26) + columnName;
130-
columnIndex /= 26;
156+
return true;
131157
}
132-
return columnName;
158+
159+
// Check custom number formats
160+
var numberingFormats = stylesPart.Stylesheet.NumberingFormats;
161+
if (numberingFormats != null)
162+
{
163+
var numberFormat = numberingFormats.Elements<NumberingFormat>()
164+
.FirstOrDefault(nf => nf.NumberFormatId != null && nf.NumberFormatId == numberFormatId);
165+
166+
if (numberFormat?.FormatCode != null)
167+
{
168+
var formatCode = numberFormat.FormatCode.Value!.ToLower();
169+
// Look for common date format indicators
170+
return formatCode.Contains("yyyy") || formatCode.Contains("mm") ||
171+
formatCode.Contains("dd") || formatCode.Contains('h') ||
172+
formatCode.Contains("m/d") || formatCode.Contains("d/m");
173+
}
174+
}
175+
176+
return false;
133177
}
134178

135-
private static string EscapeCsvValue(string value)
179+
static string EscapeCsvValue(string value)
136180
{
137-
if (string.IsNullOrEmpty(value))
138-
return "";
139-
140181
// Escape CSV special characters
141182
if (value.Contains(',') ||
142183
value.Contains('"') ||

0 commit comments

Comments
 (0)