19

c# を使用して Open XML 2.0 を操作し、大きな Excel ファイルを解析します。私が直面している問題は、解析しているセルに DataType がないことです。次に、NumberFormatId をチェックして、10 進数、数値、または日付かどうかを判断します。数値/小数と日付の正確な 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));

現在、CellFormatをチェックするよりもDataTypeがないかどうかをチェックすることでこれを行っていますが、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 を取得し、それを解析して日付かどうかを判断するのですか?

以下は、numberformat 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"
4

1 に答える 1

39

フォーマット 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  @

ただし、これらのリストはいくつかの形式のみを指定しています。この投稿によると、OpenXml Excel ファイルからの日付の読み取り、ID 値が 164 未満の形式が組み込まれています。形式のより長いリストも見つけることができます。

xlsx ファイルのフォーマット ID 値の確認

より大きな ID 値を持つ形式の場合、その定義はファイル自体の中にあります。それらを見るには、zip アーカイブ ブラウザで開き、 xlディレクトリにあるstyles.xmlファイルを見つける必要があります。または、この xlsx ファイルをOpen XML SDK 2.0 Productivity Toolsで開き、そのファイルの/xl/styles.xml/x:StyleSheetノードに移動します。

そのセクションでは、ドキュメントで定義されたフォーマットとそれに割り当てられた ID 値を確認できるはずです。フォーマットのあるパーツは次のようになります。

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

ここに保存されたフォーマットを見ると、id 値はxlsxファイルに固有である可能性があるため、おそらく同じ ID 値を使用して、2 つの異なる 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;
}

それらのいずれかが日付であるかどうかを確認したい場合、簡単な方法は、フォーマット コード (投稿したメソッドによって作成された辞書の値) にmmおよびyyの部分文字列が含まれているかどうかを確認することだと思います。

于 2012-08-14T17:47:30.133 に答える