2011-01-11 18 views
8

Próbuję odczytać dane z plików .xlsx przy użyciu SharpZipLib, aby rozpakować je (w pamięci) i odczytać wewnętrzne pliki xml. Wszystko jest w porządku, ale rozpoznaje daty - są przechowywane w formacie julean i muszę jakoś rozpoznać, czy liczba jest datą czy tylko liczbą. W innym temacie (niestety umarł i potrzebuję szybkiej odpowiedzi) poznałem pewne rzeczy od Marka Baker'a, ale to wciąż za mało ...Daty odczytu z plików Excel OpenXML

"W Excelu daty są wartością zmiennoprzecinkową ... liczba całkowita część jest liczbą dni od 1/1/1900 (lub 1/1/1904 w zależności od tego, który kalendarz jest używany), część ułamkowa stanowiąca część dnia (tj. część czasu) ... stała się nieco bardziej niezręczna przez fakt, że rok 1900 jest uważany za rok przestępny

Jedyną rzeczą odróżniającą dane od liczby jest maska ​​formatu liczbowego. Jeśli możesz odczytać maskę formatu, możesz jej użyć do określenia wartości jako daty zamiast liczby ... następnie obliczyć wartość daty/formatowanie od daty bazowej. "

„Ale nie ma atrybutu«S»dla dat zawsze ma wartość«1»Wiem, że to określa styl, ale być może;?)”

S atrybut odwołuje się styl wpisu xf w styles.xml i nie zawsze będzie to data 1 dla dat ... wszystko zależy od tego, ile różnych stylów jest używanych w skoroszycie. Styl xf z kolei odwołuje się do maski formatu liczb. Aby zidentyfikować komórkę zawierającą datę, należy wykonać styl xf -> wyszukiwanie formatu liczbowego, a następnie określić, czy ta maska ​​liczbowa ma format liczbowy daty/czasu (a nie na przykład wartość procentowa lub maska ​​z liczbowym numerem rozliczenia)

"jeszcze jedno pytanie - mam teraz patrząc na treści style.xml iw sekcji widzę elementy, takie jak:" < xf numFmtId = "14" ... applyNumberFormat = "1"/>” "< xf numFmtId =" 1 "... applyNumberFormat =" 1 "/ >", itp. Ale nie ma sekcji <numFmts> ... Czy są jakieś "standardowe" formaty? Czy po prostu coś mi brakuje? "

Czy ktoś może mi pomóc? Z góry dziękuję.

+1

Oto lista formatów danych o identyfikatorach http://msdn.microsoft.com/en-us/library/documentformat.openxml.spreadsheet.NumberingFormat(v=office.14).aspx –

+0

możliwy duplikat [Co oznacza Komórka Office Open XML zawiera wartość daty/czasu?] (Http://stackoverflow.com/questions/4730152/what-indicates-an-office-open-xml-cell-contains-a-date-time-value) – MikeTeeVee

Odpowiedz

10

Należy znaleźć sekcję numFmts gdzieś w górnej części style.xml, jako część elementu styleSheet

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> 
    <styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"> 
     <numFmts count="3"> 
      <numFmt numFmtId="164" formatCode="[$-414]mmmm\ yyyy;@" /> 
      <numFmt numFmtId="165" formatCode="0.000" /> 
      <numFmt numFmtId="166" formatCode="#,##0.000" /> 
     </numFmts> 

EDIT

Byłem dwukrotnie sprawdzając mój xlsx Code Reader (Minęło sporo czasu, odkąd zagłębiłem się w tę część biblioteki); i są wbudowane formaty. Kody formatu liczb (numFmtId) mniejsze niż 164 są "wbudowane".

Lista który mam jest niekompletny:

0 = 'General'; 
1 = '0'; 
2 = '0.00'; 
3 = '#,##0'; 
4 = '#,##0.00'; 
5 = '$#,##0;\-$#,##0'; 
6 = '$#,##0;[Red]\-$#,##0'; 
7 = '$#,##0.00;\-$#,##0.00'; 
8 = '$#,##0.00;[Red]\-$#,##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)'; 

44 = '_("$"* #,##0.00_);_("$"* \(#,##0.00\);_("$"* "-"??_);_(@_)'; 
45 = 'mm:ss'; 
46 = '[h]:mm:ss'; 
47 = 'mmss.0'; 
48 = '##0.0E+0'; 
49 = '@'; 

27 = '[$-404]e/m/d'; 
30 = 'm/d/yy'; 
36 = '[$-404]e/m/d'; 
50 = '[$-404]e/m/d'; 
57 = '[$-404]e/m/d'; 

59 = 't0'; 
60 = 't0.00'; 
61 = 't#,##0'; 
62 = 't#,##0.00'; 
67 = 't0%'; 
68 = 't0.00%'; 
69 = 't# ?/?'; 
70 = 't# ??/??'; 
+0

Tam należy zatrzymać numFmts. Czy skoroszyt został wygenerowany przy użyciu samego programu Excel? Jeśli otworzysz dany plik w MS Excel, czy rozpoznaje wartości komórki jako daty? –

+0

Tak, a komórki są sformatowane jako daty (jeśli umieściłem numer, na przykład 40180, to również konwertuje go na bieżąco). – brovar

+0

[po edycji] To wszystko wyjaśnia, dziękuję. – brovar

8

Komórki mogą mieć style. Są to uty indeksujące cellXfs w arkuszu stylów. Każdy element cellXfs zawiera zestaw atrybutów. Najważniejszy jest NumberFormatID. Jeśli jego wartość mieści się w przedziale 14-22, jest to "standardowa" data. Jeśli mieści się w przedziale 165 - 180, jest to "sformatowana" data i będzie miała odpowiedni atrybut NumberingFormat.

standardowych Termin

[X: kr = "A2" a = "2"] [X: V] 38046 [/ x: V] [/ x: c]

[X: xf numFmtId = "14" id_czcionki = "0" fillId = "0" borderId = "0" xfId = "0" applyNumberFormat = "1" /] (porządkowej pozycja 2)

sformatowany Data

[x: cr = "A4" s = "4"] [x: v] 38048 [/ x: v] [/ x: c]

[x: xf numFmtId = "166" fontId = "0" fillId = " 0 "borderId = "0" xfId = "0" applyNumberFormat = "1" /] (porządkowej pozycja 4)

[X: numFmt numFmtId = "166" formatCode = "m/s, d, @" /]

ten kod wyodrębnia listę stylów odpowiadających tym formatom daty.

private void GetDateStyles() 
    { 
    // 
    // The only way to tell dates from numbers is by looking at the style index. 
    // This indexes cellXfs, which contains NumberFormatIds, which index NumberingFormats. 
    // This method creates a list of the style indexes that pertain to dates. 
    WorkbookStylesPart workbookStylesPart = (WorkbookStylesPart) UriPartDictionary["/xl/styles.xml"]; 
    Stylesheet styleSheet = workbookStylesPart.Stylesheet; 
    CellFormats cellFormats = styleSheet.CellFormats; 

    int i = 0; 
    foreach (CellFormat cellFormat in cellFormats) 
    { 
     uint numberFormatId = cellFormat.NumberFormatId; 
     if ((numberFormatId >= 14 && numberFormatId <= 22) 
     || (numberFormatId >= 165u && numberFormatId <= 180u)) 
     { 
      _DateStyles.Add(i.ToString()); 
     } 
     i++; 
    } 
+0

Jak zdobyć UriPartDictionary? –

+0

Ok. Ja już wiem. _document = SpreadsheetDocument.Open (filePath, true); UriPartDictionary = BuildUriPartDictionary (_document); http://stackoverflow.com/a/13607098/907732 –

+0

[link: MSDN] (http://msdn.microsoft.com/en-us/library/documentformat.openxml.spreadsheet.NumberingFormat (v = office.14) .aspx) nie jest poprawnie udokumentowany. Ale POI twierdzi to samo w [link: Issue] (https://issues.apache.org/bugzilla/show_bug.cgi?id=40128). Brak oficjalnego potwierdzenia w ECMA. Jak wiem. –

4

Sugerowałbym, że numFmtId = „14” powinna być uważana za „Okna Short Data Format”, jak w Australii format ten wyświetla datę jako „dd/mm/rr”, a nie „mm/dd/yy ".

0

Istnieją dwa sposoby uzyskania formatu daty dla komórki.

Zaczynasz od przechwytywania "s" lub StyleIndex. Zwróć uwagę na datę w formacie numerycznym surowego poniżej (40667):

<row r="1"> 
    <c r="A1" s="1"> 
    <v>40667</v> 
    </c> 
</row> 

„S” atrybut w komórkach węzłów wskazuje na tablicy od zera węzłów styles.xml począwszy od 0. To jest klucz do lokalizowania format daty, jeśli taki istnieje, odwzorowujący surowe dane liczbowe. Widzisz s = 1, który wskazuje na 2 węźle xf w następujący komórce sekcję styles.xml w skoroszycie Excela formatowania:

<cellXfs count="2"> 
    <xf numFmtId="0" ... /> 
    <xf numFmtId="14" ... /> 
    </cellXfs> 

W drugim węźle można zobaczyć numFmtId = „14” wartość. To jest numberFormatID. Informuje, że jest to identyfikator potrzebny do ustalenia, w jaki sposób należy podać numer daty. Ale ta liczba wskazuje dwa możliwe miejsca dla formatu daty. Jeśli jego liczba mieści się w przedziale 14-22, jest to styl wbudowany dla daty. Jeśli jest poza tym zakresem, jego (być może) niestandardowy format daty dodany przez właściciela pliku Excel. Nie dowiesz się, dopóki nie sprawdzisz obu miejsc.

W pierwszym przypadku, jeśli jest to wartość 14-22, należy zmapować go do jednego z gotowych formatów daty, które ma każdy plik Excela (mm-dd-rr, itd.). Możesz znaleźć tę tabelę w pakiecie SDK OpenXML. Oto przykład z tych, z numFmtId odwzorowanym na wbudowanej formatów daty ....

14 mm-dd-yy 
15 d-mmm-yy 
16 d-mmm 
17 mmm-yy 
18 h:mm AM/PM 

W tym momencie wiesz, jego data i jaki format jej zostać przedstawione. Jeśli jej nie jedna te wartości, prawdopodobnie numer niestandardowy. Musisz teraz ponownie przeszukać plik styles.xml dla węzła stylu z pasującą wartością numFmtId. Węzły te będą zawierać datę niestandardowy format w następujący sposób:

<numFmts count="2"> 
     <numFmt numFmtId="164" formatCode="mm/yyyy;@" /> 
     <numFmt numFmtId="165" formatCode="0.000" /> 
     <numFmt numFmtId="166" formatCode="#,##0.000" /> 
    </numFmts> 

Zauważ, że jeśli numFmtId było 164, znaleźliście swoją datę niestandardowy format. Aby uchwycić wszystkie te szalone formaty dat, niestandardowe i wbudowane, najlepiej jest zachować zakres dopuszczalnych "formatów" jako ciągów znaków, zlokalizować swój kod formatu, a następnie sprawdzić, czy pasuje do jednego z akceptowalnych w kodzie.

Powodzenia!

Powiązane problemy