2012-08-02 15 views
12

Büyük excel dosyalarını ayrıştırmak için C# kullanarak Open XML 2.0 ile çalışma. Çalıştığım sorun, ayrıştıracağım hücrenin bir DataType I içermemesi ve ondalık, sayı veya tarih olup olmadığını belirlemek için NumberFormatId değerini kontrol etmektir. Sayılar/ondalık sayılar ve tarihler için tam NumberFormatId aralığını arıyorum. Bazı sayıların/ondalıkların 189,212,214,305 biçiminde ve 185, 194, 278 değerlerine sahip tarihler gibi yerlerin her yerinde olduğu görülüyor. Şartnamenin bu aralıkları tanımlayıp tanımlamadığını bilen var mı?C# Açık XML 2.0 NumberFormatId aralığı

Düzenlendi - Fazla Bilgi Aşağıda

xl klasörünün içindeki style.xml dosyasından 194 sayısının biçiminin bir örneğidir.

Excel sayfaları dünyanın farklı bölgelerinden geliyor, bu yüzden sayı biçimlerinin farklı olduğunu düşünüyorum, fakat çakışıyor mu? NumFmtId 194, farklı kültür ayarlarında bir tarih dışında bir şey olacak mı?

"40574" gibi c.CellValues'ı tarihlere nasıl dönüştürdüğüm aşağıda açıklanmıştır, ancak sorun "40574" bir tarih değil, bir sayı olup olmadığını nasıl anlarım? NumberFormatId bazıları benim kontrol altında olmadığında CellFormat kontrol ama sorunlar vardır daha VeriTürü varsa

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

Şu anda kontrol ederek yapıyorum. Ben nasıl sorum olacak bu Yani

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

:

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 

Düzenleme benim güncellenen gönderide

ben style.xml dosyasında bulunan değeri yazılan unuttum formatCode olsun ve bir tarih olup olmadığını belirlemek için ayrıştırmak? Aşağıda

NumberFormat derhal ayıklama penceresinden çıkışı 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

Tamsayı değerleri ve karşılık gelen biçimleri olan bir tablo içeren sayfalara bakın: http://closedxml.codeplex.com/wikipage?title=NumberFormatId%20Lookup%20Table veya http://lateral8.com/articles/2010 /6/11/openxml-sdk-20-formatting-excel-values.aspx. –

+0

Bu konuda daha fazla yardım ister misiniz, yoksa bu bağlantılar sorununuzu çözmek için yeterliydi? Eğer öyleyse, bunu bir çözüm olarak gönderebilirim :). Daha fazla bilgi isterseniz veya farklı bir şey arıyorsanız, bana bildirin ve yardım etmeye çalışacağım. –

+0

Bunun hakkında daha fazla bilgiye ihtiyacınız var. Sağlanan bağlantılar, 189,212,214,305 numaralı sorgumda listelediğim formatları kapsamaz. Tüm tarihler ile sayı/ondalık veya dizge için bir aralık aradığımdan. – maguy

cevap

23

biçimleri ID'nin Listeleri Aşağıda

biçim seçeneklerinin listesi (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 @ 
olduğunu değerleri

Hower, bu liste sadece birkaç formatı belirtiyor. Bu yazara göre: Reading dates from OpenXml Excel files, ID değeri 164'den küçük bir biçim yerleşiktir. Ayrıca daha uzun bir format listesi bulabilirsiniz. daha Kimlik değerlerle biçimleri için xlsx dosyası

yılında

kontrol etme biçimleri kimliği değerleri, dosyanın kendisi içinde kendi tanımlarını bulabilirsiniz. Onları görmek için, bir zip arşivi tarayıcısıyla açın olmalı ve xl dizinde styles.xml dosyayı bulmak. Alternatif olarak bu xlsx dosyasını Open XML SDK 2.0 Productivity Tools ile açın ve bu dosyanın /xl/styles.xml/x:StyleSheet düğümüne gidin.Bu bölümde

, bunları atanan kimlik değerleri ile birlikte belgede tanımlanan biçimleri görmek gerekir. biçimleriyle parçası buna benzer görünmelidir:
... 
<x:numFmts count="1"> 
    <x:numFmt numFmtId="166" formatCode="yy/mm/dd;@" /> 
</x:numFmts> 
... 

buraya kaydedilir formatlar baktığımızda

, o id vlaues bir xlsx dosyaya özgü olabilir gibi görünüyor, bu yüzden muhtemelen aynı kimlik değeri farklı tanımlamak için kullanılabilir iki farklı xlsx dosyasında formatlar. Ancak, yerleşik int formatları için önceden tanımlanmışlardır, bu yüzden tüm dosyalarda aynı olmalıdır. Eğer dosyada veya ek bilgi bu biçimleri bulma konusunda yardıma ihtiyacınız olursa

, bana bildirin.

Ayrıca bu belgede sayı biçimleri hakkında biraz daha bilgi bulabilirsiniz

DÜZENLEME: http://msdn.microsoft.com/en-us/library/documentformat.openxml.spreadsheet.numberingformat.aspx.

Sen xlsx dosya içinde tanımlanan tüm biçimlerini içeren bir sözlük almak için bu kodu kullanabilirsiniz II

DÜZENLEME:

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

o herhangi biri olup olmadığını kontrol etmek istiyorsanız bir tarih, ben formatı kodu (Yayınladığım yöntemiyle oluşturulan sözlükte değer) mm içeriyorsa basit bir şekilde doğrulanması olacağını varsayalım ve yy

+1

Mükemmel LukasZ M. Bu hile yapmalı. Bu konuda yaptığınız tüm çalışmaları gerçekten takdir ediyorum. – maguy

+0

Sorun değil, yardımcı olmaktan mutluluk duyuyorum :). Cevabımı işaretlediğin ve kurtardığın için teşekkürler :). –

+0

Teşekkür ederim Lukasz. Çok yardımcı oldu. Hayır Excel'de tarih hücre tipini tanıyabilirim. –