2013-09-26 1 views
2

Я должен использовать некоторые документы xlsx. Я читал Reading a date from xlsx using open xml sdk и http://www.dotnetperls.com/fromoadate. Большинство моих столбцов - это тексты (общие строки), но есть некоторые числа (целые числа), и у меня также есть некоторые даты и даты. Я использую OpenXML SDK 2.5.Как отличить рядовые числа от номеров даты OLE Automation в OpenXML SpreadSheet?

Моя проблема заключается в том, что я не знаю, как отличить фактические числа от дат. Оба они имеют DataType из null, а текстовое число представлено в свойстве Text свойства ячейки.

Некоторый код:

using (var xlsxStream = assembly.GetManifestResourceStream("Checklist.xlsx")) 
    using (var spreadsheetDocument = SpreadsheetDocument.Open(xlsxStream, false)) 
    { 
    var workbookPart = spreadsheetDocument.WorkbookPart; 
    var sharedStringTable = workbookPart.SharedStringTablePart.SharedStringTable; 
    var worksheetPart = workbookPart.WorksheetParts.First(); 
    var sheetData = worksheetPart.Worksheet.Elements<SheetData>().First(); 
    string text; 
    foreach (Row r in sheetData.Elements<Row>()) 
    { 
     foreach (Cell c in r.Elements<Cell>()) 
     { 
     if (c.CellValue != null) 
     { 
      text = c.CellValue.Text; 
      if (c.DataType != null) 
      { 
      if (c.DataType.Value == CellValues.SharedString) 
      { 
       int tableIndex = int.Parse(text); 
       text = sharedStringTable.ChildElements[tableIndex].InnerText; 
      } 
      // note: the date cells do not have c.DataType.Value == CellValues.Date 
      // Their c.DataType is null, if they are OLE Automation date numbers 
      } 
      // So here I am, and I'd need to know if the number supposed to be an 
      // OLE Automation date or a number, so I can transform it if needed. 
      //if (it's a date) // <- ????? 
      //{ 
      // double dateDouble = double.Parse(text); 
      // DateTime dateTime = DateTime.FromOADate(dateDouble); 
      // text = dateTime.ToShortDateString(); 
      //} 
      Console.Write(text + " "); 
     } 
     else 
     { 
      Console.Write("NULL" + " "); 
     } 
     } 
     Console.WriteLine(); 
    } 
    Console.WriteLine(); 
    Console.ReadKey(); 

ответ

7

Я просто наткнулся на аналогичный вопрос, и это не так легко проверить, содержит ли ячейка значение даты/времени см Using cell format to determine a cell contains date/time value, но проблема не заканчивается со встроенным число форматов, мне также нужно было обрабатывать пользовательские форматы. В OpenXML SDK 2.5 нет никаких полезных утилит, поэтому мне пришлось писать свои собственные (не поддерживает тайские форматы даты и времени).

public class ExcelHelper 
{ 
    static uint[] builtInDateTimeNumberFormatIDs = new uint[] { 14, 15, 16, 17, 18, 19, 20, 21, 22, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 45, 46, 47, 50, 51, 52, 53, 54, 55, 56, 57, 58 }; 
    static Dictionary<uint, NumberingFormat> builtInDateTimeNumberFormats = builtInDateTimeNumberFormatIDs.ToDictionary(id => id, id => new NumberingFormat { NumberFormatId = id }); 
    static Regex dateTimeFormatRegex = new Regex(@"((?=([^[]*\[[^[\]]*\])*([^[]*[ymdhs]+[^\]]*))|.*\[(h|mm|ss)\].*)", RegexOptions.Compiled); 

    public static Dictionary<uint, NumberingFormat> GetDateTimeCellFormats(WorkbookPart workbookPart) 
    { 
     var dateNumberFormats = workbookPart.WorkbookStylesPart.Stylesheet.NumberingFormats 
      .Descendants<NumberingFormat>() 
      .Where(nf => dateTimeFormatRegex.Match(nf.FormatCode.Value).Success) 
      .ToDictionary(nf => nf.NumberFormatId.Value); 

     var cellFormats = workbookPart.WorkbookStylesPart.Stylesheet.CellFormats 
      .Descendants<CellFormat>(); 

     var dateCellFormats = new Dictionary<uint, NumberingFormat>(); 
     uint styleIndex = 0; 
     foreach (var cellFormat in cellFormats) 
     { 
      if (cellFormat.ApplyNumberFormat != null && cellFormat.ApplyNumberFormat.Value) 
      { 
       if (dateNumberFormats.ContainsKey(cellFormat.NumberFormatId.Value)) 
       { 
        dateCellFormats.Add(styleIndex, dateNumberFormats[cellFormat.NumberFormatId.Value]); 
       } 
       else if (builtInDateTimeNumberFormats.ContainsKey(cellFormat.NumberFormatId.Value)) 
       { 
        dateCellFormats.Add(styleIndex, builtInDateTimeNumberFormats[cellFormat.NumberFormatId.Value]); 
       } 
      } 

      styleIndex++; 
     } 

     return dateCellFormats; 
    } 

    // Usage Example 
    public static bool IsDateTimeCell(WorkbookPart workbookPart, Cell cell) 
    { 
     if (cell.StyleIndex == null) 
      return false; 

     var dateTimeCellFormats = ExcelHelper.GetDateTimeCellFormats(workbookPart); 

     return dateTimeCellFormats.ContainsKey(cell.StyleIndex); 
    } 
} 
+0

Спасибо, что направили меня в нужном направлении. Вы достигаете большего, чем мне нужно. Короткий ответ на мой вопрос заключается в том, что я ** должен обратить внимание на атрибуты стиля и найти стиль перекрестных ссылок и выбрать формат, основанный на этом **. Краткий неполный список ответов Марка Бейкера в другой теме, которую вы уделили, дает хорошее представление. Однако у меня не было времени попробовать решение. Поскольку я знал фиксированную схему моих 7 разных входов XLS, моим уродливым обходным решением было жесткое подключение схем к моему коду. –

+0

Теперь это было очень полезно! –

+0

Это наиболее полный ответ на вопрос «какие ячеистые даты» я нашел в течение нескольких часов веб-исследований. – SAJ14SAJ