正如您在问题中指出的那样,格式与使用样式表中的数字格式的单元格值分开存储。
您应该能够扩展用于格式化日期的代码以包括数字格式化。本质上,您需要获取与您已经在阅读的cellFormat.NumberFormatId.Value 对应的NumberingFormat。 NumberingFormat 可以在 styleSheet.NumberingFormats 元素中找到。
一旦你有了这个,你就可以访问NumberingFormat的FormatCode属性,然后你可以使用它来格式化你认为合适的数据。
不幸的是,这种格式使用起来并不那么简单。首先,根据 MSDN here,并非所有格式都写入文件,所以我想您必须将这些格式放在可访问的位置并根据您拥有的 NumberFormatId 加载它们。
其次,格式字符串的格式与 C# 不兼容,因此您需要进行一些操作。格式布局的详细信息可以在 MSDN here找到。
我已经拼凑了一些示例代码来处理您在问题中遇到的货币情况,但您可能需要更多地考虑将 excel 格式字符串解析为 C# 格式。
private static string GetCellValue(SharedStringTablePart stringTablePart, DocumentFormat.OpenXml.Spreadsheet.Cell cell, DocumentFormat.OpenXml.Spreadsheet.Stylesheet styleSheet)
{
string value = cell.CellValue.InnerXml;
if (cell.DataType != null && cell.DataType.Value == DocumentFormat.OpenXml.Spreadsheet.CellValues.SharedString)
{
return stringTablePart.SharedStringTable.ChildElements[Int32.Parse(value)].InnerText;
}
else
{
if (cell.StyleIndex != null)
{
DocumentFormat.OpenXml.Spreadsheet.CellFormat cellFormat = (DocumentFormat.OpenXml.Spreadsheet.CellFormat)styleSheet.CellFormats.ChildElements[(int)cell.StyleIndex.Value];
int formatId = (int)cellFormat.NumberFormatId.Value;
if (formatId == 14) //[h]:mm:ss
{
DateTime newDate = DateTime.FromOADate(double.Parse(value));
value = newDate.Date.ToString(CultureInfo.InvariantCulture);
}
else
{
//find the number format
NumberingFormat format = styleSheet.NumberingFormats.Elements<NumberingFormat>()
.FirstOrDefault(n => n.NumberFormatId == formatId);
double temp;
if (format != null
&& format.FormatCode.HasValue
&& double.TryParse(value, out temp))
{
//we have a format and a value that can be represented as a double
string actualFormat = GetActualFormat(format.FormatCode, temp);
value = temp.ToString(actualFormat);
}
}
}
return value;
}
}
private static string GetActualFormat(StringValue formatCode, double value)
{
//the format is actually 4 formats split by a semi-colon
//0 for positive, 1 for negative, 2 for zero (I'm ignoring the 4th format which is for text)
string[] formatComponents = formatCode.Value.Split(';');
int elementToUse = value > 0 ? 0 : (value < 0 ? 1 : 2);
string actualFormat = formatComponents[elementToUse];
actualFormat = RemoveUnwantedCharacters(actualFormat, '_');
actualFormat = RemoveUnwantedCharacters(actualFormat, '*');
//backslashes are an escape character it seems - I'm ignoring them
return actualFormat.Replace("\"", ""); ;
}
private static string RemoveUnwantedCharacters(string excelFormat, char character)
{
/* The _ and * characters are used to control lining up of characters
they are followed by the character being manipulated so I'm ignoring
both the _ and * and the character immediately following them.
Note that this is buggy as I don't check for the preceeding
backslash escape character which I probably should
*/
int index = excelFormat.IndexOf(character);
int occurance = 0;
while (index != -1)
{
//replace the occurance at index using substring
excelFormat = excelFormat.Substring(0, index) + excelFormat.Substring(index + 2);
occurance++;
index = excelFormat.IndexOf(character, index);
}
return excelFormat;
}
给定一张使用货币格式化的值为570.80999999999995 的表格(在英国),我得到的输出是£570.81。