Kodda bir Excel (xlsx) dosyası oluşturmak için iyi bir tasarım deseni nedir?


12

Daha fazla bilgi için aşağıdaki Güncellememe bakın.


Bazen bazı verileri bir Excel dosyası (xlsx formatı) olarak çıktılamak zorunda olduğum projelerim var. İşlem genellikle:

  1. Kullanıcı uygulamamdaki bazı düğmeleri tıklıyor

  2. Kodum bir DB sorgusu çalıştırır ve sonuçları bir şekilde işler

  3. Kodum, Excel com birlikte çalışma kitaplıkları veya bazı üçüncü taraf kitaplıkları (ör. Aspose.Cells) kullanarak bir * .xlsx dosyası oluşturur

Bunu nasıl çevrimiçi yapmak için kolayca kod örnekleri bulabilirsiniz, ancak bunu yapmak için daha sağlam bir yol arıyorum. Kodumun korunabilir ve kolay anlaşılır olmasını sağlamak için kodumun bazı tasarım ilkelerini izlemesini istiyorum.


İşte benim xlsx dosyası oluşturmak için ilk denemem şöyle görünüyordu:

var wb = new Workbook();
var ws = wb.Worksheets[0];
ws.Cells[0, 0].Value = "Header";
ws.Cells[1, 0].Value = "Row 1";
ws.Cells[2, 0].Value = "Row 2";
ws.Cells[3, 0].Value = "Row 3";
wb.Save(path);

Artıları: Fazla değil. Çalışıyor, bu yüzden iyi.

Eksileri:

  • Hücre başvuruları sabit kodlu, bu yüzden kodum boyunca sihirli numaralar var.
  • Çok sayıda hücre referansını güncellemeden sütun ve satır eklemek veya kaldırmak zordur.
  • Bazı üçüncü taraf kütüphanelerini öğrenmem gerekiyor. Bazı kütüphaneler diğer kütüphaneler gibi kullanılır, ancak yine de sorunlar olabilir. Aspose.Cells 0 tabanlı hücre başvurusu kullanırken com birlikte çalışma kitaplıkları 1 tabanlı hücre başvurusu kullanan bir sorun vardı.

Yukarıda listelediğim bazı eksilerini ele alan bir çözüm. Bir veri tablosunu, hücre manipülasyonuna kazmadan ve diğer hücre referanslarını bozmadan hareket ettirilebilen ve değiştirilebilen kendi nesnesi olarak ele almak istedim. İşte bazı sözde kod:

var headers = new Block(new string[] { "Col 1", "Col 2", "Col 3" });
var body = new Block(new string[,]
    {
        { "Row 1", "Row 1", "Row 1" },
        { "Row 2", "Row 2", "Row 2" },
        { "Row 3", "Row 3", "Row 3" }
    });

body.PutBelow(headers);

Bu çözümün bir parçası olarak, bir Blocks kapsayıcısı alan ve verileri bir .xlsx dosyası olarak çıktılamak için gereken hücre manipülasyonlarını gerçekleştiren bazı BlockEngine nesnesine sahip olacağım. Bir Block nesnesinin üzerine biçimlendirilmiş olabilir.

Artıları:

  • Bu, ilk kodumdaki sihirli sayıların çoğunu kaldırır.
  • Bahsettiğim BlockEngine nesnesinde hücre manipülasyonu hala gerekli olmasına rağmen, bu birçok hücre manipülasyon kodunu gizler.
  • E-tablonun diğer bölümlerini etkilemeden satır eklemek ve kaldırmak çok daha kolaydır.

Eksileri:

  • Sütun eklemek veya kaldırmak hala zor. İki ve üç sütunun konumunu değiştirmek istersem, doğrudan hücre içeriğini değiştirmem gerekirdi. Bu durumda, bu sekiz düzenleme ve dolayısıyla bir hata yapmak için sekiz fırsat olurdu.
    • Bu iki sütun için herhangi bir biçimlendirmem varsa, bunu da güncellemeliyim.
  • Bu çözüm yatay blok yerleşimini desteklemez; Sadece bir bloğu diğerinin altına yerleştirebilirim. Tabii ki olabilirdi tableRight.PutToRightOf(tableLeft), ancak tableRight ve tableLeft'in farklı sayıda satırı varsa sorunlara neden olabilir. Tablo yerleştirmek için motorun diğer tüm tablolardan haberdar olması gerekir. Bu benim için gereksiz yere karmaşık görünüyor.
  • Yine de üçüncü taraf kodu öğrenmem gerekiyor, ancak Block nesneleri ve bir BlockEngine üzerinden soyutlama katmanı aracılığıyla kod, ilk denememden daha az üçüncü taraf kütüphanesine daha az bağlı olacak. Gevşek bir şekilde çok sayıda farklı biçimlendirme seçeneğini desteklemek istersem, muhtemelen çok fazla kod yazmak zorunda kalırdım; BlockEngine'm büyük bir karmaşa olurdu.

İşte farklı bir rota izleyen bir çözüm. İşlem şu şekildedir:

  1. Rapor verilerimi alıp, seçtiğim formatta bir xml dosyası oluşturuyorum.

  2. Daha sonra xml dosyasını bir Excel 2003 XML Elektronik Tablosu dosyasına dönüştürmek için bir xsl dönüşümü kullanıyorum.

  3. Oradan sadece bir üçüncü taraf kitaplığı kullanarak xml Elektronik Tablosu bir xlsx dosyasına dönüştürmek.

Benzer bir işlemi açıklayan ve kod örnekleri içeren bu sayfayı buldum .

Artıları:

  • Bu çözüm neredeyse hiç hücre manipülasyonu gerektirmez. Bunun yerine manipülasyonlarınızı yapmak için xsl / xpath kullanırsınız. Tablodaki iki sütunu takas etmek için xsl dosyasındaki tüm sütunları, hücre değiştirmeyi gerektiren diğer çözümlerimin aksine taşırsınız.
  • Hala bir Excel 2003 XML Elektronik Tablosunu xlsx dosyasına dönüştürebilen üçüncü taraf bir kütüphaneye ihtiyacınız olsa da, kütüphaneye ihtiyacınız olan tek şey budur. Üçüncü taraf kitaplığını çağıracak, yazmanız gereken kod miktarı azdır.
  • Bence bu çözüm anlaşılması en kolay ve en az miktarda kod gerektirir.
    • Verileri kendi xml biçimimde oluşturan kod basit olacaktır.
    • Xsl dosyası yalnızca Excel 2003 XML Elektronik Tablosu karmaşık olduğundan karmaşık olacaktır. Ancak xsl dosyasının çıktısını kontrol etmek kolaydır: çıktıyı Excel'de açın ve hata mesajlarını kontrol edin.
    • Örnek Excel 2003 XML Elektronik Tablosu dosyaları oluşturmak kolaydır: istediğiniz xlsx dosyasına benzeyen bir elektronik tablo oluşturun ve Excel Excel XML Elektronik Tablosu olarak kaydedin.

Eksileri:

  • Excel 2003 XML Elektronik Tabloları belirli özellikleri desteklemez. Örneğin sütun genişliklerine otomatik sığdıramazsınız. Üstbilgi veya altbilgiye resim ekleyemezsiniz. Ortaya çıkan xlsx dosyasını pdf'ye dışa aktaracaksanız, pdf yer imlerini ayarlayamazsınız. (Hücre yorumlarını kullanarak bunun için bir düzeltme hackledim.). Bunu üçüncü taraf kitaplığınızı kullanarak yapmanız gerekir.
  • Excel 2003 XML Elektronik Tablolarını destekleyen bir kitaplık gerektirir.
  • 11 yaşında bir MS Office dosya biçimi kullanır.

Not: xlsx dosyalarının aslında xml dosyaları içeren zip dosyaları olduğunu anlıyorum, ancak xml biçimlendirmesi benim amacım için çok karmaşık görünüyor.


Son olarak, SSRS'yi içeren çözümleri araştırdım, ancak bu benim amacım için çok şişkin görünüyor.


İlk soruma geri dönelim, kodda Excel dosyaları oluşturmak için iyi bir tasarım deseni nedir ?. Birkaç çözüm düşünebilirim, ama hiçbiri ideal gibi görünmüyor. Her birinin dezavantajları vardır.


Güncelleme: Bu yüzden hem XLEX dosyalarını hem de BlockEngine çözümümü ve XML Elektronik Tablo çözümümü denedim. İşte benim düşüncelerim:

  • BlockEngine çözümü:

    • Bu sadece alternatifleri göz önünde bulundurarak çok fazla kod gerektirir.
    • Yanlış bir ofset olsaydı bir bloğun üzerine başka bir blok yazmayı çok kolay buldum.
    • Başlangıçta biçimlendirmenin blok düzeyinde eklenebileceğini belirtmiştim. Bunu, biçimlendirmeyi blok içeriğinden ayrı yapmaktan daha iyi bulmadım. İçeriği ve biçimlendirmeyi birleştirmenin iyi bir yolunu düşünemiyorum. Onları ayrı tutmanın iyi bir yolunu da bulamıyorum. Bu sadece bir karmaşa.
  • XML Elektronik Tablosu çözümü:

    • Şimdilik bu çözümü kullanıyorum.
    • Bu çözümün çok daha az kod gerektirdiğini yineliyor. BlockEngine'i Excel'in kendisiyle etkili bir şekilde değiştiriyorum. Yer imleri ve sayfa sonları gibi özellikler için hala bir saldırıya ihtiyacım var.
    • XML Elektronik Tablosu biçimi titizdir, ancak küçük bir değişiklik yapmak ve sonuçları favori Diff programınızdaki mevcut bir dosyayla karşılaştırmak kolaydır. Ve bir kez kendine özgü bir şey bulduktan sonra, onu yerine koyabilir ve oradan unutabilirsiniz.
    • Hala bu çözümün eski bir Excel dosya biçimine dayandığından endişeleniyorum.
    • Oluşturduğum XSLT dosyasının çalışması kolaydır. Biçimlendirme ile uğraşmak burada BlockEngine çözümüyle olduğundan çok daha basittir.

Yanıtlar:


7

Gerçekten sizin için iyi çalışan bir şey istiyorsanız, "gereksiz yere karmaşık" fikrine alışmanızı öneririm ... Microsoft Office dosya formatlarıyla uğraşmanın doğası budur.

"Bloklar" fikrinizi beğenirim ... Tablo gibi sütunlar ve Satırlar gibi alt sınıf blok nesnelerini hücre kavramından bağımsız hale getiririm. Ardından, bunları XSLS dosyalarına dönüştürmek için blok motorunuzu kullanın.

Geçmişte OpenXML SDK'yı başarıyla kullandım , ancak belgeleri okumaya ve baştan başlamaya çalışmayın. Bunun yerine, Excel'de tam olarak istediğiniz şeyin bir kopyasını oluşturun, kaydedin ve sağlanan Document Reflector aracını kullanarak inceleyin. Belgeyi oluşturmanız için gereken C # kodunu verir, daha sonra öğrenebileceğiniz ve değiştirebileceğiniz.


Office belgeleri "gereksiz yere karmaşık" DEĞİLDİR - muazzam bir dizi işlem, biçimlendirme, işlevsellik vb.
warren

5
Dosya biçimlerinin kendileri ile gereksiz derecede karmaşık olduğunu iddia etmiyorum , onlarla çalışmanın tartıştığını iddia ediyorum . Örneğin, OpenXML SDK'yı kullanmak, öğelerin ekleneceği sihirli sırayı bilmenizi gerektirir ... örneğin, bir sunuya slayt düzeni eklemek işe yaramaz. Önce slayda, ardından sunuma eklemeniz gerekir. Neden? Çünkü Microsoft kütüphaneleri bu şekilde kodladı. Yönetilmesi gereken birçok garip dairesel referans da var. Biçimin karmaşıklığa ihtiyacı olduğunu anlıyorum, ancak onunla çalışmak çok acı verici olmamalı.
mgw854

3

İşte geçmişte sık kullandığım bir çözüm:

  • şablon olarak başlık ve sütunlar için varsayılan biçimlendirme ve belki de başlık hücreleri için biçimlendirme de dahil olmak üzere tüm sütun başlıklarını içeren normal bir Excel belgesi (genellikle xlsx biçiminde) oluşturun.

  • bu şablonu programınızın kaynaklarına gömün. Çalışma zamanında ilk adım, şablonu yeni bir dosya olarak ayıklamak ve hedef klasöre yerleştirmektir.

  • Verileri yeni oluşturulan xlsx'e doldurmak için Interop veya üçüncü taraf kitaplığı kullanın. Sabit kodlanmış sütun numaralarına başvurmayın, bunun yerine doğru sütunları tanımlamak için bazı meta veriler (örneğin sütun başlıkları) kullanın.

Artıları:

  • Block yaklaşımınız gibi bir şey artık daha iyi çalışıyor. Örneğin, sütun değiştirme: doğru sütunlar başlıkları tarafından tanımlandığından, blok kodunuzdaki hiçbir şeyi değiştirmenize gerek yoktur

  • sütunlarınız benzersiz bir biçimlendirmeye sahip olduğu sürece, biçimlendirmenin çoğu şablonunuzu değiştirerek doğrudan Excel'de yapılabilir. Bu, size WYSIWYG hissi verirken, Excel'de mevcut herhangi bir biçimlendirme seçeneğini kullanma özgürlüğü ile birlikte kod yazmanıza gerek kalmaz

Eksileri:

  • yine de bir üçüncü taraf lib veya Interop kullanmanız gerekir. Interop'un yavaş olduğunu söylemiş miydim?

  • şablonunuzdaki sütun başlıkları değiştiğinde, kodunuzu da uyarlamanız gerekir (ancak bu, beklenen sütunlar eksikse sinyal veren bir doğrulama yordamına sahip olarak kolayca tespit edilebilir)

  • aynı sütunda farklı hücrelerin dinamik olarak biçimlendirilmesi gerektiğinde, yine de kodda bununla uğraşmanız gerekir

Genel bir ipucu olarak, hangi yaklaşımı seçerseniz seçin: mizanpajı içerikten ayırmanın ve bildirim çözümlerinden yararlanmanın avantajları vardır.


0

Dikkate alınması gereken iki şey vardır:

  • Belirli bir biçimde dosya oluşturmanın karmaşıklığı
  • Dosyanın içeriğinin değişmesi gerektiğinde kodun kırılmaya karşı duyarlılığı.

İlk ile ilgili olarak:

Oluşturmanız gereken e-tablolar herhangi bir biçimlendirme veya formül içermiyorsa , gerçek bir XLSX yerine bir CSV veya Sekmeyle Sınırlandırılmış dosya oluşturmak oldukça basittir. Excel bu dosyaları genellikle varsayılan olarak birçok bilgisayarda açar. Bu, sütunlar ve satırlar etrafında sabit kodlama yapmanıza yardımcı olmaz, ancak Excel nesne modelini manipüle etmek için ekstra işten tasarruf etmenizi sağlar.

Biçimlendirmeye veya formüllere ihtiyacınız varsa, özellikle çok "sabit kodlanmamış" bir elektronik tablo oluşturursanız, Excel nesne modeliyle çalışmak makul bir yoldur. Başka bir deyişle, e-tablonuz göreceli formüller ve aralık adları uygun şekilde kullanıyorsa, sihirli sayıların daha az kodlanmasıyla birlikte gidebilir.

İkincisi ile ilgili olarak:

Sabit kodlanmış satır ve sütun referansları ile hücre bazında çalışabilir veya forhücre popülasyonunu genelleştirmek için diziler / Liste koleksiyonları ve döngülerle çalışabilirsiniz .


Orijinal sorumda, biçimlendirme ve yazdırma seçeneklerini ve bunun gibi çözümü kontrol etmek istediğimi açıkça bilmiyordum. İkinci nokta ile ilgili olarak, benim atıfta bulunduğum şeyin benim çözümümde anlattığım şey olduğunu düşünüyorum BlockEngine. IList<IBusinessObject>Bir Blocknesneyi alıp tükürebilirim . Artıları ve eksileri hala aynı olurdu.
user2023861 15:14
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.