【问题标题】:C# Open XML 2.0 NumberFormatId rangeC# Open XML 2.0 NumberFormatId 范围
【发布时间】:2012-08-02 15:48:38
【问题描述】:

使用 C# 使用 Open XML 2.0 来解析大型 excel 文件。我遇到的问题是我正在解析的单元格没有 DataType 我然后检查 NumberFormatId 以确定它是十进制、数字还是日期。我正在寻找数字/小数与日期的确切 NumberFormatId 范围。它们似乎无处不在,一些数字/小数的格式为 189,212,214,305,日期的值为 185、194、278 等。有人知道规范是否定义了这些范围吗?

已编辑 - 更多信息

下面是 xl 文件夹中 style.xml 文件中 194 的数字格式示例。

Excel 表格来自世界不同地区,所以我认为数字格式不同,但它们是否重叠? numFmtId 194 会不是不同文化背景下的日期吗?

下面是我如何将“40574”之类的 c.CellValues 转换为日期,但问题是我如何知道“40574”是日期而不是数字?

 DateTime.FromOADate(Convert.ToDouble(c.CellValue.Text));

目前我通过检查是否没有 DataType 而不是检查 CellFormat 来执行此操作,但是当我检查的某些 NumberFormatId 中没有时会出现问题。

    private Object FormatCellValue(Cell c, SharedStringTable ssTable, CellFormats cellFormats)
            {
                if (c.CellValue != null)
                {
                    // If there is no data type, this must be a string that has been formatted as a number
                    if (c.DataType == null)
                    {
                        CellFormat cf;
                        if (c.StyleIndex == null)
                        {
                            cf = cellFormats.Descendants<CellFormat>().ElementAt<CellFormat>(0);
                        }
                        else
                        {
                            cf = cellFormats.Descendants<CellFormat>().ElementAt<CellFormat>(Convert.ToInt32(c.StyleIndex.Value));
                        }


                        if ((cf.NumberFormatId >= 14 && cf.NumberFormatId <= 22) ||
                            (cf.NumberFormatId >= 165 && cf.NumberFormatId <= 180) || 
                                cf.NumberFormatId == 278 || cf.NumberFormatId == 185 || cf.NumberFormatId == 196 || 
                                cf.NumberFormatId == 217 || cf.NumberFormatId == 326) // Dates
                        {

                            try
                            {

                                DateTime dt;
                                dt = DateTime.FromOADate(Convert.ToDouble(c.CellValue.Text));

...CODE CONTINUES

编辑

在我更新的帖子中,我忘记发布在 style.xml 文件中找到的值:

<numFmt numFmtId="323" formatCode="mmm/yy;@"/>

因此,我的问题是如何获取 formatCode 并对其进行解析以确定它是否是日期?

下面是数字格式 323 的即时调试窗口的输出

{DocumentFormat.OpenXml.Spreadsheet.CellFormat}
    base {DocumentFormat.OpenXml.OpenXmlCompositeElement}: {DocumentFormat.OpenXml.Spreadsheet.CellFormat}
    Alignment: {DocumentFormat.OpenXml.Spreadsheet.Alignment}
    ApplyAlignment: "1"
    ApplyBorder: "1"
    ApplyFill: "1"
    ApplyFont: "1"
    ApplyNumberFormat: "1"
    ApplyProtection: "1"
    BorderId: "64"
    ExtensionList: null
    FillId: "0"
    FontId: "83"
    FormatId: "37992"
    LocalName: "xf"
    NumberFormatId: "323"
    PivotButton: null
    Protection: {DocumentFormat.OpenXml.Spreadsheet.Protection}
    QuotePrefix: "1"

【问题讨论】:

  • 查看那些包含整数值和相应格式的表格的页面:closedxml.codeplex.com/…lateral8.com/articles/2010/6/11/…
  • 您是否需要更多帮助,或者这些链接足以解决您的问题?如果是这样,我可以将其作为解决方案发布:)。如果您想了解更多信息或正在寻找不同的东西,请告诉我,我会尽力提供帮助。
  • 需要更多信息。提供的链接不涵盖我在问题 189,212,214,305 等中列出的格式。我正在寻找所有日期与数字/小数或字符串的范围。
  • 能否请您发布您正在解析的代码 sn-p 的 xls 文件的 xml,显示您如何检查 NumberFormatId 属性?这可能会有所帮助。
  • 我刚刚更新了我之前的帖子,提供了更多信息。

标签: c# openxml openxml-sdk


【解决方案1】:

格式 ID 值列表

以下是格式选项列表 (source)

ID  Format Code
0   General
1   0
2   0.00
3   #,##0
4   #,##0.00
9   0%
10  0.00%
11  0.00E+00
12  # ?/?
13  # ??/??
14  d/m/yyyy
15  d-mmm-yy
16  d-mmm
17  mmm-yy
18  h:mm tt
19  h:mm:ss tt
20  H:mm
21  H:mm:ss
22  m/d/yyyy 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  @

但是,这些列表仅指定了几种格式。根据这篇帖子:Reading dates from OpenXml Excel files,内置了 ID 值小于 164 的格式。您还可以在那里找到更长的格式列表。

检查 xlsx 文件中的格式 ID 值

对于具有更大 ID 值的格式,您可以在文件本身中找到它们的定义。要查看它们,您应该使用 zip 存档浏览器打开它并在 xl 中找到 styles.xml 文件> 目录。或者,使用 Open XML SDK 2.0 Productivity Tools 打开此 xlsx 文件并导航到该文件的 /xl/styles.xml/x:StyleSheet 节点。

在该部分中,您应该能够看到文档中定义的格式以及分配给它们的 ID 值。带有格式的部分应该类似于:

...
<x:numFmts count="1">
    <x:numFmt numFmtId="166" formatCode="yy/mm/dd;@" />
</x:numFmts>
...

查看此处保存的格式,似乎 id vlaues 可以特定于 xlsx 文件,因此可能相同的 ID 值可用于在两个不同的 xlsx 文件中定义不同的格式。但是,对于内置格式,它们是预定义的,因此在所有文件中应该是相同的。

如果您在查找文件中的这种格式或其他信息方面需要任何帮助,请告诉我。

编辑

您还可以在本文档中找到有关数字格式的更多信息:http://msdn.microsoft.com/en-us/library/documentformat.openxml.spreadsheet.numberingformat.aspx

编辑二

您可以使用此代码获取包含 xlsx 文件中定义的所有格式的字典:

private Dictionary<uint, String> BuildFormatMappingsFromXlsx(String fileName)
{
    Dictionary<uint, String> formatMappings = new Dictionary<uint, String>();

    using (SpreadsheetDocument document = SpreadsheetDocument.Open(fileName, true))
    {
        var stylePart = document.WorkbookPart.WorkbookStylesPart;

        var numFormatsParentNodes = stylePart.Stylesheet.ChildElements.OfType<NumberingFormats>();

        foreach (var numFormatParentNode in numFormatsParentNodes)
        {
            var formatNodes = numFormatParentNode.ChildElements.OfType<NumberingFormat>();
            foreach (var formatNode in formatNodes)
            {
                formatMappings.Add(formatNode.NumberFormatId.Value, formatNode.FormatCode);
            }
        }
    }

    return formatMappings;
}

如果您想检查其中任何一个是否是日期,我想一种简单的方法是验证格式代码(由我发布的方法创建的字典中的值)是否包含 mmyy 子字符串。

【讨论】:

  • 完美的 LukasZ M。这应该可以解决问题。非常感谢您为此所做的所有工作。
  • 没问题,我很乐意提供帮助:)。感谢您标记和支持我的回答:)。
  • 谢谢卢卡斯。这很有帮助。不,我可以在 Excel 中识别日期单元格类型。
  • 如果我想要一个包含 xlsx 文件中存在的每列格式的字典怎么办?
  • 如果你想获得特定列和使用的格式之间的关联,你可以使用格式ID。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-28
  • 1970-01-01
  • 1970-01-01
  • 2015-09-11
  • 1970-01-01
  • 2018-03-03
相关资源
最近更新 更多