我无法确定Cell是一个约会对象。
我注意到DataType为null所以我无法区分它是否是一个日期的数字。
我正在使用下一个代码来提取单元格:
WorksheetPart worksheetPart = (WorksheetPart)workbookPart.GetPartById(worksheetId);
SheetData sheetData = worksheetPart.Worksheet.GetFirstChild<SheetData>();
Row[] rows = worksheetPart.Worksheet.Descendants<Row>().ToArray();
for (int i = 0; i < rows.Length; i++)
{
List<Cell> cells = rows[i].Elements<Cell>().ToList();
foreach (var cell in cells)
{
if (cell.DataType != null && cell.DataType.Value == CellValues.Date)
//this line is not hit for some reason
}
}
}
我错过了什么吗?
答案 0 :(得分:6)
简而言之,它是null,因为它应该是数字和日期类型。
上的OpenXML文档对于数字和日期类型,DataType属性的值为null。 它包含字符串的值CellValues.SharedString,和 布尔值的CellValues.Boolean。
使用 CellFormat 上的 NumberFormatId ,可以区分日期和数字格式。诀窍是找到什么id映射到什么格式。您可以通过创建新的Excel文件并将单元格设置为相关格式(即日期)来找出要使用的格式:
然后使用7zip提取excel文件并查看xl / styles.xml文件:
在上图中,您可以看到此格式ID 14转换为短日期。有关格式的完整列表,请参阅ECMA-376 documentation for Office Open XML formats(表格应隐藏在第4部分的某处)。
我为最常见的formatIds创建了一个枚举:
private enum Formats
{
General = 0,
Number = 1,
Decimal = 2,
Currency = 164,
Accounting = 44,
DateShort = 14,
DateLong = 165,
Time = 166,
Percentage = 10,
Fraction = 12,
Scientific = 11,
Text = 49
}
然后,您可以创建一个帮助函数,以您希望的方式获得格式化的值:
private static string GetFormattedCellValue(WorkbookPart workbookPart, Cell cell)
{
if (cell == null)
{
return null;
}
string value = "";
if (cell.DataType == null) // number & dates
{
int styleIndex = (int)cell.StyleIndex.Value;
CellFormat cellFormat = (CellFormat)workbookPart.WorkbookStylesPart.Stylesheet.CellFormats.ElementAt(styleIndex);
uint formatId = cellFormat.NumberFormatId.Value;
if (formatId == (uint)Formats.DateShort || formatId == (uint)Formats.DateLong)
{
double oaDate;
if (double.TryParse(cell.InnerText, out oaDate))
{
value = DateTime.FromOADate(oaDate).ToShortDateString();
}
}
else
{
value = cell.InnerText;
}
}
else // Shared string or boolean
{
switch (cell.DataType.Value)
{
case CellValues.SharedString:
SharedStringItem ssi = workbookPart.SharedStringTablePart.SharedStringTable.Elements<SharedStringItem>().ElementAt(int.Parse(cell.CellValue.InnerText));
value = ssi.Text.Text;
break;
case CellValues.Boolean:
value = cell.CellValue.InnerText == "0" ? "false" : "true";
break;
default:
value = cell.CellValue.InnerText;
break;
}
}
return value;
}
答案 1 :(得分:1)
先前的回答指出格式已在第4部分中进行了记录,但显然它们已移至第1部分。我通过搜索#,##0.00
找到了它们。对于数字格式而言,它们当前采用18.8.30 numFmt(数字格式)格式,这些格式暗含了formatCode值,而不是显式保存在文件中。有关此工作簿中的数字格式,请参见 18.8.31 numFmts(数字格式),其中包含一系列numFmt记录,其中
每个numFmt记录定义一种特定的数字格式,指示如何格式化和呈现单元格的数值。
以下是所有语言的暗含的formatCode属性。
ID formatCode
0 General
1 0
2 0.00
3 #,##0
4 #,##0.00
9 0%
10 0.00%
11 0.00E+00
12 # ?/?
13 # ??/??
14 mm-dd-yy
15 d-mmm-yy
16 d-mmm
17 mmm-yy
18 h:mm AM/PM
19 h:mm:ss AM/PM
20 h:mm
21 h:mm:ss
22 m/d/yy h:mm
37 #,##0 ;(#,##0)
38 #,##0 ;[Red](#,##0)
39 #,##0.00;(#,##0.00)
40 #,##0.00;[Red](#,##0.00)
45 mm:ss
46 [h]:mm:ss
47 mmss.0
48 ##0.0E+0
49 @
还有许多其他依赖语言的隐式格式代码,例如:
28 [$-404]e"年"m"月"d"日" m"月"d"日"
答案 2 :(得分:0)
你试过cell.HasValue
吗?因为int和Datetime并不总是可空的,所以它取决于代码的编写方式。