HotXLS, pivotField ve cacheField ögeleri ECMA-376 Part 1 §18.10 şemasına göre doğrulayan XLSX pivot tablo tanımları yazar: axis öznitelikleri ST_Axis tokenları axisRow, axisCol ve axisPage'i kullanır, değer alanındaki alanlar dataField="1" taşır, item listeleri hiçbir zaman boş değildir ve cache alanları sayısal bir numFmtId saklar. v2.384.33'ten beri okuyucu, eskiden yanlış yaptığı şema varsayılanlarını da uygular
Bu temizliğin ardındaki hatalar ortak bir utanç verici özellik taşır: hiçbiri bir testi hiç başarısızlığa uğratmadı. HotXLS bir pivot yazıyor, HotXLS geri okuyor, her alan doğru eksene düşüyor ve gidiş dönüş paketi yıllarca yeşil kalıyordu. Sorun, yazıcı ile okuyucunun sessizce özel bir lehçede anlaşmış olmasıydı. Delphi'den kurulan bir pivot, onu üreten bileşene güzel görünürken CT_PivotField ve CT_CacheField'e karşı yapılan bir denetim geçersiz sayım tokenları, şemanın yasakladığı boş bir öge ve Excel'in beklediği ama hiç almadığı bayraklar çıkarıyordu. Pivotları sunucuda üretip Excel'de açacak ya da kendi ayrıştırıcılarına verecek kişilere gönderiyorsanız, tek sayılan sözleşme şemadır; kendi okuyucunuzun neyi bağışladığı değil
HotXLS gidiş dönüşleri yanlış axis tokenlarını neden hiç yakalamadı?
HotXLS gidiş dönüşleri yanlış axis tokenlarını hiç yakalamadı, çünkü okuyucu her iki yazımı da kabul ediyordu. Eski XlsxPivotAxisAttr, İngilizceye doğal okunan ama şemada bulunmayan axis="rowAxis", colAxis ve pageAxis değerlerini basıyordu; ST_Axis tam olarak dört değer tanımlar: axisRow, axisCol, axisPage ve axisValues. Bu arada lxPivotXml.pas içindeki PivotAxisFromToken hem şema tokenını hem uyduruk olanı eşliyordu; böylece her kendi kendine test geçiyordu. Yazıcı artık yalnızca şema tokenlarını basıyor; okuyucu ise eski yazımları kabul etmeye devam eder, böylece önceki HotXLS sürümlerinin kaydettiği dosyalar yerleşimleri bozulmadan yüklenir
<!-- v2.384.33 öncesi: geçersiz ST_Axis değeri, boş CT_Items -->
<pivotField axis="rowAxis" defaultSubtotal="1"><items count="0"></items></pivotField>
<!-- v2.384.33'ten beri -->
<pivotField axis="axisRow" defaultSubtotal="1">
<items count="4"><item x="0"/><item x="1"/><item x="2" h="1"/><item t="default"/></items>
</pivotField>
CT_PivotField, eski yazıcının atladığı neyi gerektirir?
CT_PivotField, eski BuildPivotTableXml'in ya atladığı ya yanlış yaptığı üç şey gerektirir. Birincisi, değer alanında toplanan bir alan bunu kendi tanımında dataField="1" ile söylemelidir; yazıcı artık o bayrağı DataFields içindeki bir girdinin referans verdiği her alana koyar, yalnızca <dataFields> listesinde değil. İkincisi, CT_Items en az bir item gerektirir; itemsiz bir alan artık boş bir <items count="0"> almaz ve tüm öge hiç yazılmaz. Üçüncüsü, her item durumunu korur: gizli item için h="1" (TXLSPivotItem.IsHidden) ve kapatılmış ayrıntılar için sd="0" (IsDetailHidden); eski yazıcı ikisini de her kaydetmede düşürüyordu
İnce nokta, sondaki ara toplam itemlarıdır. Bir alanın itemları olduğunda Excel, veri itemlarının ardından her ara toplam fonksiyonu için bir ekstra item listeler; bunlar ST_ItemType ile tiplenir: otomatik ara toplam için <item t="default"/>, açık olanlar için sum, countA, avg, max, min, product, count, stdDev, stdDevP, var ve varP. HotXLS bu girdileri kaydetme anında TXLSPivotField.Subtotals'dan türetir ve items count'a sayar. AddPivotTable ile kurulan alanlar boş bir Subtotals kümesiyle başlar; bu, defaultSubtotal="0" ve sonda item olmadan yazar; rapor ara toplam istiyorsa onları açıkça isteyin. Adlandırma tuzağına dikkat: xlpsCount countA'ya (tüm girdiler), xlpsCountNums count'a (yalnızca sayılar) eşlenir
uses
lxHandleX, lxPivot;
var
Book : TXLSXWorkbook;
Sheet : TXLSXWorksheet;
Pivot : TXLSPivotTable;
Region: TXLSPivotField;
begin
Book := TXLSXWorkbook.Create;
try
Book.Open('orders.xlsx');
Sheet := Book.Sheets[1]; // 1 tabanlı, XLS motoru gibi
Pivot := Sheet.AddPivotTable('Data!$A$1:$D$800', 3, 6, 'RegionTotals');
if Pivot = nil then
raise Exception.Create('Bad source range or anchor');
Region := Pivot.AddRowField('Region'); // böyle bir alan yokken nil
if Region <> nil then
Region.Subtotals := [xlpsDefault, xlpsAverage]; // -> t="default", t="avg"
Pivot.AddColumnField('Quarter');
Pivot.AddDataFieldByName('Revenue', xlpaSum); // Revenue'a dataField="1" bayrağını koyar
Book.SaveAs('orders-pivot.xlsx');
finally
Book.Free;
end;
end;
HotXLS ara toplam itemlarını ve şema varsayılanlarını şimdi nasıl okur?
HotXLS okuyucusu artık t özniteliği bulunan ve değeri data olmayan her item'i atlar; çünkü ara toplam, genel toplam ve boş girdileri cache indeksi taşımaz. v2.384.34 öncesinde bu girdiler CacheItemIndex'i -1 yapılmış sıradan itemlar olarak yükleniyordu; Excel'in yaptığı bir pivot, hiçbir yere işaret etmeyen hayalet üyelerle dönüyordu ve Items üzerinde gezen her kod onları elle filtrelemek zorundaydı. Yazıcı sondaki girdileri Subtotals'dan yeniden kurduğuna göre okuyucunun işi onları o kümeye çevirmektir, veri olarak tutmak değil
İkinci okuyucu düzeltmesi, bulunmayan özniteliklerle ilgilidir. Şemada CT_PivotField üzerindeki defaultSubtotal ile CT_SharedItems üzerindeki containsString varsayılanı true'dur ve Excel o varsayılanı tuttuklarında bunları yazmaz. HotXLS eksik bir özniteliği false okuyordu; bu da Excel'in kaydettiği her pivotun yüklemede sessizce varsayılan ara toplamını kaybedeceği ve düz metin bir cache alanının dize yerine karma olarak sınıflanacağı anlamına geliyordu. Bu, axis hatasının ayna görüntüsüdür: her özniteliği her zaman açıkça yazan bir yazıcı varsayılan yolunu hiç çalıştırmaz; yolu yalnızca başka bir üreticinin dosyaları açığa çıkarır
numFmtId="General" cache alanlarında neden geçersizdi?
numFmtId="General" değeri geçersizdi, çünkü ST_NumFmtId bir biçim adı değil işaretsiz tamsayıdır. Eski cache yazıcısı bu dizeyi her cacheField'e, kullanıcının Hücreleri Biçimlendir penceresinde gördüğü adı ödünç alarak, sabit kodluyordu. HotXLS artık cache alanının NumberFormat'ını sayı olarak yazar; bir şey atamadıysa bu 0'dır (yerleşik General biçimi). Öznitelikleri şemadan tiplenen katı bir ayrıştırıcı eski değeri tümüyle reddeder ve tam da onarım penceresine dönüşen başarısızlık sınıfı budur; Excel onarım isteminin ardındaki OPC ve işaretleme kuralları makalesi bu pencerelerin nasıl tetiklendiğini anlatır
65535. satırın altındaki pivot tablolar neden kesiliyordu?
65536. satıra yerleşen ya da onun altındaki XLSX pivot tabloları kesiliyordu, çünkü paylaşılan pivot modeli FirstRow, LastRow, FirstHeaderRow, FirstDataRow ve sütun karşılıklarını Word olarak saklıyor, satır kaydırma kodu onları Min(.., High(Word)) ile kısılıyordu. Bu, 16 bitin yeterli olduğu BIFF8 SxView kaydından kalma bir şeydi; oysa bir XLSX sayfası 1.048.576 satıra kadar çıkar. v2.384.37'den beri TXLSPivotTable üzerindeki bu özellikler Integer'dır, kıyımlar kalkmıştır ve değerleri yalnızca BIFF8 yazıcısı daraltır. TXLSXWorksheet.AddPivotTable ve AddPivotTableCopy, 1..1048576 satır ve 1..16384 sütun dışında bir çapa için ya da uzantısı ızgarayı aşacak bir kopya için artık nil döndürür
var
Pivot: TXLSPivotTable;
Check: TXLSXWorkbook;
begin
// 70001. satır eskiden 16 bitlik aralığa sarılıyordu; artık kaydetme ve yüklemede hayatta kalır
Pivot := Sheet.AddPivotTable('Data!$A$1:$D$800', 70001, 1, 'LateTotals');
if Pivot = nil then
Exit; // çapa sayfa dışında ya da kaynak aralık çözümlenemiyor
Pivot.AddRowField('Region');
Pivot.AddDataFieldByName('Revenue', xlpaSum);
Book.SaveAs('late.xlsx');
Check := TXLSXWorkbook.Create;
try
Check.Open('late.xlsx');
Pivot := Check.Sheets[1].PivotTables.FindByName('LateTotals');
Assert((Pivot <> nil) and (Pivot.FirstRow = 70001));
finally
Check.Free;
end;
end;
Klasik XLS motoru eş düzeltmeyi v2.384.38'de aldı. Onun modeli ham 0 tabanlı SxView ve DConRef değerlerini saklıyor ve AddPivotTable çapalarını olduğu gibi geçiyordu; dokümantasyon, demolar ve XLSX motoru ise Cells[Row, Col] gibi 1 tabanlı hücreler kullanıyordu. Her iki motor da artık modelde 1 tabanlı konum tutar; BIFF8 okuyucusu 1 ekler, yazıcı kayıt sınırında 1 çıkarır; böylece (0, 0)'a çapa atan kodun (1, 1)'e taşınması gerekir, çünkü klasik AddPivotTable 1..65536 satır ve 1..256 sütun dışındaki bir çapa için artık nil döndürür; yeni çağrı, eskinin yazdığı baytların aynısını yazar. Kayıt yerleşiminin kendisi değişmedi ve klasik .xls pivot tablolarının ardındaki BIFF8 SX kayıtları makalesinde anlatılıyor
Kendi okuyucunuza değil şemaya göre doğrulayın
Ders pivotların ötesine geneller: hoşgörülü bir okuyucu yazıcı ihlallerini gizler; kendi kodunuzdan geçen bir gidiş dönüş tutarlılık kanıtlar, doğruluk değil. Buradaki her hata, toleranslı taraf ile hatalı tarafın aynı kütüphanede yaşaması sayesinde hayatta kaldı. Bu sınıf kusuru gerçekten yakalayan denetimler şunlardır: üretilen parçaların şema doğrulaması, Excel'in ürettiği ve öznitelikleri varsayılanlarında atlanmış dosyaların okuyucunuzdan geçirilmesi ve ayrıştırılmış sonuç yerine tam tokenı sabitleyen test verileri. API üzerinden kurduğunuz pivotlar — hesaplanan alanlarla XLSX pivot tabloları kurma ve yenileme makalesinde gösterilen hesaplanan alanlar, hesaplanan itemlar ve yüzde-of-toplam yerleşimleri dahil — kod değişikliği olmadan düzeltilmiş XML'i alır; Excel dosyalarından yüklenen pivotlar ise siz onları değiştirene dek özgün parçalarını yeniden oynatmaya devam eder
Bu düzeltmelerin tümü güncel HotXLS Delphi elektronik tablo bileşeninde gelir; bileşen XLS, XLSX ve pivot tablolarını makinede Excel ya da COM otomasyonu olmadan Delphi ve C++Builder'dan okur ve yazar