2012-08-02 41 views
12

Trabajar con Open XML 2.0 usando C# para analizar grandes archivos de Excel. Problema que me estoy encontrando es que la celda que estoy analizando no tiene un DataType. Luego verifico NumberFormatId para determinar si es decimal, número o fecha. Estoy buscando el rango exacto NumberFormatId para números/decimales contra fechas. Parecen estar por todos lados, algunos números/decimales tienen formatos de 189,212,214,305 y fechas con valores de 185, 194, 278, etc. ¿Alguien sabe si la especificación define estos rangos?C# Open XML 2.0 NumberFormatId rango

Editado - Más información

A continuación se muestra un ejemplo del formato de número de 194 a partir del archivo style.xml dentro de la carpeta xl.

Las hojas de Excel son de diferentes regiones del mundo, así que estoy pensando que los formatos de los números son diferentes, pero ¿se superponen? ¿Será numFmtId 194 algo diferente a una fecha en diferentes configuraciones de cultura?

A continuación se muestra cómo estoy convirtiendo c.CellValues ​​como "40574" a las fechas, pero el problema es ¿cómo sé si "40574" es una fecha y no un número?

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

Actualmente estoy haciendo esto comprobando si no hay un Tipo de datos de comprobar el CellFormat pero hay problemas cuando algunos de los IdFormatoNumerico no están en mi cheque.

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 

Editar

En mi post actualizado que se olvidó de publicar el valor que encontré en el archivo style.xml:

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

Así que con esto mi pregunta sería ¿cómo puedo obtener el formatCode y analizarlo para determinar si se trata de una fecha?

A continuación se muestra la salida de la ventana de depuración inmediata del 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

Eche un vistazo a las páginas que contienen una tabla con valores enteros y los formatos correspondientes: http://closedxml.codeplex.com/wikipage?title=NumberFormatId%20Lookup%20Table o http://lateral8.com/articles/2010 /6/11/openxml-sdk-20-formatting-excel-values.aspx. –

+0

¿Desea más ayuda sobre esto o esos enlaces fueron suficientes para resolver su problema? Si es así, podría publicarlo como una solución :). Si desea obtener más información o está buscando algo diferente, hágamelo saber e intentaré ayudarlo. –

+0

Necesita más información sobre esto. Los enlaces proporcionados no cubren los formatos que he enumerado en mi pregunta 189,212,214,305, etc. Estoy buscando un rango para todas las fechas frente a los números/decimales o cadenas. – maguy

Respuesta

23

Listas de formatos ID valores

A continuación se muestra la lista de opciones de formato (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, esas listas especifican solo varios formatos. De acuerdo con esta publicación: Reading dates from OpenXml Excel files, el formato con un valor ID inferior a 164 está incorporado. También puede encontrar una lista más larga de formatos allí.

Comprobación de formatos valores de ID en xlsx

Para los formatos con mayores valores de ID, puede buscar sus definiciones dentro del propio archivo. Con el fin de verlos, debe abrirlo con un navegador archivo zip y encontrar styles.xml archivo en xl directorio. De forma alternativa, abra este archivo xlsx con Open XML SDK 2.0 Productivity Tools y navegue hasta el nodo /xl/styles.xml/x:StyleSheet del archivo.

En esa sección, debería poder ver los formatos definidos en su documento junto con los valores de ID asignados. La parte con los formatos debe ser similar a esto:

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

En cuanto a los formatos guardados aquí, parece que vlaues id puede ser específico para un archivo xlsx, por lo que probablemente el mismo valor de ID se puede utilizar para definir diferentes formatos en dos archivos xlsx diferentes. Sin embargo, para los formatos built-int están predefinidos, por lo que debería ser el mismo en todos los archivos.

Si necesita ayuda para encontrar este formato en su archivo o información adicional, hágamelo saber.

EDITAR

También puede encontrar más información sobre los formatos de número en este documento: http://msdn.microsoft.com/en-us/library/documentformat.openxml.spreadsheet.numberingformat.aspx.

EDITAR II

Puede utilizar este código para obtener un diccionario que contiene todos los formatos definidos en el xlsx archivo:

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

Si desea comprobar si alguno de ellos es una fecha, supongo que una manera simple sería verificar si el código de formato (valor en el diccionario creado por el método que publiqué) contiene mm y yy subseries.

+1

Perfecto LukasZ M. Eso debería hacer el truco. Realmente aprecio todo el trabajo que hicieron en esto. – maguy

+0

No hay problema, me complace ayudar :). Gracias por marcar y subir mi respuesta :). –

+0

Gracias Lukasz. Fue muy útil. No, puedo reconocer el tipo de celda de fecha en Excel. –

Cuestiones relacionadas