2011-01-11 41 views
8

Tôi đang cố đọc dữ liệu từ tệp .xlsx bằng SharpZipLib để giải nén nó (trong bộ nhớ) và đọc các tệp xml bên trong. Mọi thứ đều ổn nhưng công nhận ngày tháng - chúng được lưu trữ ở định dạng julean và tôi cần phải bằng cách nào đó nhận ra nếu một số là một ngày hoặc chỉ một số. Trong một chủ đề khác (tiếc là nó đã chết và tôi cần câu trả lời nhanh) Tôi đã biết một số điều từ Mark Baker, nhưng vẫn chưa đủ ...Đọc ngày từ các tệp OpenXml Excel

"Excel stores date as a float value ... the integer một phần là số ngày kể từ 1/1/1900 (hoặc 1/1/1904 tùy thuộc vào lịch nào đang được sử dụng), phần phân đoạn là tỷ lệ của một ngày (tức là phần thời gian) ... làm cho hơi khó xử hơn bởi thực tế là năm 1900 được coi là năm nhuận 1.

Điều duy nhất phân biệt dữ liệu từ một số là mặt nạ định dạng số. Nếu bạn có thể đọc mặt nạ định dạng, bạn có thể sử dụng để xác định giá trị làm ngày thay vì một số ... sau đó tính giá trị/định dạng ngày từ ngày cơ sở. "

"Nhưng không thuộc tính 's' cho những ngày luôn luôn có giá trị của '1' Tôi biết nó xác định phong cách, nhưng có lẽ;?)"

Các s thuộc tính tham chiếu một mục nhập xf kiểu trong styles.xml và không phải lúc nào cũng là mục nhập 1 cho các ngày ... tất cả phụ thuộc vào số lượng kiểu khác nhau đang được sử dụng trong sổ làm việc. Phong cách xf lần lượt tham chiếu một mặt nạ định dạng số. Để xác định ô có chứa ngày, bạn cần thực hiện tra cứu kiểu xf -> numberformat, sau đó xác định xem mặt nạ định dạng số đó có phải là mặt nạ định dạng số ngày/giờ (thay vì, ví dụ, tỷ lệ phần trăm hoặc mặt nạ định dạng số)

"thêm một câu hỏi - tôi bây giờ nhìn vào nội dung của style.xml và trong phần tôi thấy các yếu tố như:" < xf numFmtId = "14" ... applyNumberFormat = "1"/>", "< xf numFmtId =" 1 "... applyNumberFormat =" 1 "/ >", v.v. nhưng không có <numFmts> phần ... Có định dạng "chuẩn" nào không? Hay tôi chỉ thiếu một thứ gì đó? "

Ai đó có thể giúp tôi không? Cảm ơn trước.

+1

Đây là danh sách các định dạng ngày Id http://msdn.microsoft.com/en-us/library/documentformat.openxml.spreadsheet.NumberingFormat(v=office.14).aspx –

+0

có thể trùng lặp của [Điều gì biểu thị Office Open XML Cell có chứa giá trị Ngày/Giờ?] (Http://stackoverflow.com/questions/4730152/what-indicates-an-office-open-xml-cell-contains-a-date-time-value) – MikeTeeVee

Trả lời

10

Bạn nên tìm ra numFmts phần đâu đó gần đỉnh của style.xml, như là một phần của phần tử 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

Tôi đã đôi kiểm tra mã độc giả xlsx của tôi (nó đã được một thời gian dài kể từ khi tôi delved vào đó một phần của thư viện); và có các định dạng được tích hợp sẵn. Mã định dạng số (numFmtId) nhỏ hơn 164 là "tích hợp sẵn".

Danh sách mà tôi có là không đầy đủ:

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

Đó là nơi numFmts nên được tổ chức. Sổ làm việc có được tạo bằng chính Excel không? Nếu bạn mở tệp được đề cập trong MS Excel, nó có nhận ra các giá trị ô là ngày không? –

+0

Có và các ô được định dạng là ngày (nếu tôi đặt một số như 40180 ở đó, nó cũng chuyển đổi nó thành ngày). – brovar

+0

[sau khi chỉnh sửa] Điều đó giải thích mọi thứ, cảm ơn bạn. – brovar

8

Các tế bào có thể có phong cách. Đây là những gợi ý rằng chỉ mục cellXfs trong styleSheet. Mỗi mục cellXfs chứa một tập hợp các thuộc tính. Điều quan trọng nhất là NumberFormatID. Nếu giá trị của nó nằm trong khoảng 14-22 thì đó là ngày "chuẩn". Nếu nó nằm trong khoảng 165 - 180, nó là ngày "được định dạng" và sẽ có thuộc tính NumberingFormat tương ứng.

Chuẩn ngày

[x: cr = "A2" s = "2"] [x: v] 38.046 [/ x: v] [/ x: c]

[x: xf numFmtId = "14" fontId = "0" fillId = "0" borderId = "0" xfId = "0" applyNumberFormat = "1" /] (vị trí thứ 2)

định dạng ngày

[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" /] (vị trí thứ 4)

[x: numFmt numFmtId = "166" formatCode = "m/d; @" /]

này mã trích xuất một danh sách các ID phong cách tương ứng với các định dạng ngày tháng này.

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

Làm thế nào để tải UriPartDictionary? –

+0

Ok. Tôi đã biết. _document = SpreadsheetDocument.Open (tệpPath, true); UriPartDictionary = BuildUriPartDictionary (_document); http://stackoverflow.com/a/13607098/907732 –

+0

[liên kết: MSDN] (http://msdn.microsoft.com/en-us/library/documentformat.openxml.spreadsheet.NumberingFormat (v = office.14) .aspx) không được ghi lại đúng cách. Nhưng POI tuyên bố tương tự trong [link: Issue] (https://issues.apache.org/bugzilla/show_bug.cgi?id=40128). Chưa có xác nhận chính thức nào về ECMA. Như tôi biết. –

4

tôi sẽ đề nghị rằng numFmtId = "14" nên được coi là "Windows định dạng ngắn ngày" như ở Úc định dạng này sẽ hiển thị một ngày như, "dd/mm/yy", và không phải là "mm/dd/yy ".

0

Có hai cách để có định dạng ngày cho ô.

Bạn bắt đầu bằng cách lấy "s" hoặc StyleIndex. Lưu ý ngày ở định dạng nguyên số dưới đây (40.667):

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

Các "s" thuộc tính trong các tế bào nút trỏ đến một mảng không dựa trên các nút styles.xml bắt đầu từ 0. Đây là chìa khóa để định vị định dạng ngày, nếu có, sẽ ánh xạ tới dữ liệu ngày tháng thô. Bạn thấy đấy s = 1, trỏ đến nút xf 2 trong tế bào sau định dạng phần styles.xml của bảng tính Excel của bạn:

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

Trong nút thứ hai bạn nhìn thấy numFmtId = "14" giá trị. Đó là numberFormatID. Nó cho bạn biết rằng đó là id cần thiết để xác định những gì số ngày của bạn sẽ được trình bày in Nhưng số đó trỏ đến hai nơi có thể cho các định dạng ngày. Nếu số của nó nằm trong khoảng 14-22, nó được xây dựng theo kiểu cho đến ngày. Nếu nó nằm ngoài phạm vi của nó (có thể) một định dạng ngày tùy chỉnh được thêm bởi chủ sở hữu tệp excel. Bạn sẽ không biết cho đến khi bạn kiểm tra cả hai nơi.

Trong trường hợp đầu tiên, nếu giá trị của nó là 14-22, bạn sẽ cần ánh xạ nó đến một trong các định dạng ngày được tạo sẵn mà mỗi tệp excel có (mm-dd-yy, v.v.). Bạn có thể định vị bảng đó trong SDK OpenXML. Dưới đây là một ví dụ của những người có numFmtId ánh xạ tới các built-in định dạng ngày ....

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

Tại thời điểm này, bạn có biết một ngày và những gì định dạng của nó được trình bày trong. Nếu nó không nằm trong số những giá trị đó, có khả năng là số tùy chỉnh. Và bây giờ bạn phải tìm kiếm lại tệp styles.xml cho một nút kiểu có giá trị numFmtId phù hợp. Các nút đó sẽ chứa định dạng ngày tùy chỉnh như sau:

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

Lưu ý rằng nếu numFmtId của bạn là 164, bạn đã tìm thấy định dạng ngày tùy chỉnh của nó. Vì vậy, để nắm bắt tất cả các định dạng ngày tháng điên rồ này, tùy chỉnh và tích hợp, đặt cược tốt nhất của bạn là duy trì một loạt các định dạng có thể chấp nhận được như chuỗi, định vị mã định dạng của bạn, sau đó xem nó có khớp với một trong những định dạng được chấp nhận trong mã của bạn hay không.

Chúc may mắn!

Các vấn đề liên quan