2012-08-02 43 views
12

Praca z Open XML 2.0 przy użyciu C# do parsowania dużych plików Excela. Problem, na który się natknę, to komórka, którą parsuję, nie ma DataType I, następnie sprawdź NumberFormatId, aby określić, czy jest to liczba dziesiętna, liczba czy data. Szukam dokładnego zakresu NumberFormatId dla liczb/liczb dziesiętnych vs dat. Wygląda na to, że niektóre cyfry/cyfry dziesiętne mają format 189,212,214,305, a daty mają wartości 185, 194, 278 itd. Czy ktoś wie, czy specyfikacja określa te zakresy?C# Open XML 2.0 NumberFormatId range

Zmieniano - Więcej informacji

Poniżej jest przykład formatu numer 194 z pliku style.xml w folderze xl.

Arkusze programu Excel pochodzą z różnych regionów świata, więc myślę, że formaty liczbowe są różne, ale czy nakładają się na siebie? Czy numFmtId 194 będzie czymś innym niż data na różnych ustawieniach kultury?

Poniżej znajduje się sposób konwertowania c.CellValues ​​takich jak "40574" na daty, ale problem polega na tym, że wiem, czy "40574" jest datą, a nie liczbą?

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

Obecnie robię to poprzez sprawdzenie, czy nie ma TypDanych niż sprawdzić CellFormat ale istnieją problemy, gdy niektóre z NumberFormatId nie są w moim czeku.

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 

Edit

W moim zaktualizowanej postu zapomniałem odpowiedzieć wartość znalazłem w pliku style.xml:

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

Więc z tym moje pytanie byłoby jak mogę uzyskać formatCode i przeanalizować go, aby ustalić, czy jest to data?

Poniżej jest wyjście z bezpośrednim oknie debugowania w 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" 
+1

Spójrz na te strony zawierające tabelę z wartościami całkowitymi i odpowiadającymi formatami: http://closedxml.codeplex.com/wikipage?title=NumberFormatId%20Lookup%20Table lub http://lateral8.com/articles/2010 /6/11/openxml-sdk-20-formatowanie-excel-values.aspx. –

+0

Czy potrzebujesz pomocy w tej sprawie, czy te linki wystarczyły do ​​rozwiązania Twojego problemu? Jeśli tak, mógłbym napisać to jako rozwiązanie :). Jeśli potrzebujesz więcej informacji lub szukasz czegoś innego, daj mi znać, a ja postaram się pomóc. –

+0

Potrzebujesz więcej informacji na ten temat. Podane linki nie obejmują formatów wymienionych w moim pytaniu 189,212,214,305 itd. Szukam zakresu dla wszystkich dat vs liczb/liczb dziesiętnych lub łańcuchów. – maguy

Odpowiedz

23

Listy formatach ID ceni

Poniżej znajduje się lista opcji formatowania (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 @ 

Hower, lista ta określa tylko kilka formatów. Zgodnie z tym postem: Reading dates from OpenXml Excel files, format z wartością ID mniejszą niż 164 są wbudowane. Można również znaleźć dłuższą listę formatów tam.

Sprawdzanie formaty wartości ID w pliku xlsx

dla formatów o większych wartościach identyfikacyjnych, można znaleźć ich definicje wewnątrz samego pliku. Aby je zobaczyć, należy otworzyć go w przeglądarce archiwum zip i znaleźć styles.xml plik w xl katalogu. Alternatywnie otwórz ten plik xlsx za pomocą Open XML SDK 2.0 Productivity Tools i przejdź do tego pliku w węźle /xl/styles.xml/x:StyleSheet.

W tej sekcji powinny być widoczne formaty zdefiniowane w dokumencie wraz z przypisanymi im wartościami ID. Część z formatami powinien wyglądać podobnie do tego:

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

Patrząc formatów zapisanych tutaj wydaje się, że vlaues ID może być specyficzne dla xlsx pliku, więc prawdopodobnie ta sama wartość ID może być używany do definiowania różnych formaty w dwóch różnych plikach xlsx. Jednak w przypadku wbudowanych formatów są one predefiniowane, więc powinny być takie same we wszystkich plikach.

Jeśli potrzebujesz pomocy w znalezieniu tego formatu w swoim pliku lub dodatkowych informacji, daj mi znać.

EDIT

Można również znaleźć więcej informacji na temat formatów liczba w tym dokumencie: http://msdn.microsoft.com/en-us/library/documentformat.openxml.spreadsheet.numberingformat.aspx.

EDIT II

Można użyć tego kodu, aby uzyskać słownik zawierający wszystkie formaty zdefiniowane w xlsx pliku:

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; 
} 

Jeśli chcesz sprawdzić, czy któryś z nich jest data, przypuszczam, że prostym sposobem byłoby sprawdzenie, czy kod formatu (wartość w słowniku utworzonym przez metodę, którą napisałem) zawiera mm i yy podciągów.

+1

Perfect LukasZ M. To powinno załatwić sprawę. Naprawdę doceniam całą pracę, którą wykonałeś w tej sprawie. – maguy

+0

Nie ma problemu, z przyjemnością pomogę :). Dziękuję za zaznaczenie i przegłosowanie mojej odpowiedzi :). –

+0

Dziękuję Lukasz. To było bardzo pomocne. Nie mogę rozpoznać typu komórki daty w Excelu. –