XLSX'te bir shared formula takipçisi, hiçbir formül metni taşımaz. <f t="shared" si="N"/> elemanı, sayfanın başka bir yerindeki bir master hücreyi işaret eder ve okuyucu, master formülü satır ve sütun farkına göre kaydırarak metni yeniden inşa etmelidir. Delphi ve C++Builder için HotXLS Component, bu genişletmeyi açılış anında yapar, böylece her takipçi eksiksiz bir formül bildirir
Gerçek dünyadaki bir XLSX'i üçüncü taraf bir kütüphanede yükleyip bin formülden oluşan bir sütunun tam olarak bir hücrede metin, diğer 999'unda boş dizeler bulduysanız, bu özelliği yanlış taraftan tanımışsınızdır. Hiçbir şey bozuk değildir. Dosya, ECMA-376'nın izin verdiği şeyi yapıyordur ve okuyucu basitçe XML'in durduğu noktada durmuştur
Shared formula hücresi neden boş?
Çünkü biçim kasıtlı olarak formülü bir kez saklar. ECMA-376 Bölüm 1 ve ISO/IEC 29500-1'de, <f> elemanı (§18.3.1.40), ST_CellFormulaType türünde bir t özniteliği taşır ve shared değeri, bu hücrenin si özniteliğiyle tanımlanan bir gruba katıldığı anlamına gelir. Gruptaki tam olarak bir hücre, master, ayrıca grubun uygulandığı aralığı veren bir ref özniteliği taşır ve yalnızca o hücre formül metnini eleman içeriği olarak taşır. Gruptaki diğer her hücre bir takipçidir. t="shared"'ı ve aynı si'yi tekrarlar ve eleman içeriği boştur. Excel bu grupları agresif biçimde yazar, çünkü 200.000 satırlık bir sütunun aşağı doldurulması, 200.000 formül dizesinden bir dize artı 199.999 küçük yer tutucu elemana çöker. Tasarruf gerçektir ve maliyet tamamen okuyucuya düşer: genişletme olmadan, takipçinin kendi başına hiçbir anlamı yoktur
Kaydırma bir metin kopyası değil bir çeviridir
HotXLS, aynı si altında kayıtlı master'ı bularak, master çapasından geçerli hücreye satır ve sütun deltasını hesaplayarak ve master formülündeki her referansı o deltayla çevirerek bir takipçiyi çözer. Göreli boyutlar hareket eder, mutlak boyutlar etmez ve karışık referanslar yalnızca mutlak olmayan yarılarını hareket ettirir. Dize hazır bilgileri tamamen atlanır, bu yüzden içinde "A1" metnini barındıran bir formül, o metni her takipçide değişmeden tutar
const
// xl/worksheets/sheet1.xml, trimmed to the interesting cells
SheetXml: WideString=
'<row r="1"><c r="A1"><v>1</v></c>'+
'<c r="B1"><f t="shared" si="4" ref="B1:B3">'+
'A1+$A$1+A$1+$A1+"A1"+SUM(A1:A2)</f><v>7</v></c></row>'+
'<row r="2"><c r="B2"><f t="shared" si="4"/><v>8</v></c></row>'+
'<row r="3"><c r="B3"><f t="shared" si="4"></f><v>9</v></c></row>';
var
Wb: TXLSXWorkbook;
Sh: TXLSXWorksheet;
begin
Wb:= TXLSXWorkbook.Create;
try
Wb.Open(FileName);
Sh:= Wb.Sheets[1];
// Master, verbatim
// B1 -> A1+$A$1+A$1+$A1+"A1"+SUM(A1:A2)
// Follower one row down: relative row moves, absolute row frozen,
// the mixed A$1 keeps its row, and the literal stays a literal
// B2 -> A2+$A$1+A$1+$A2+"A1"+SUM(A2:A3)
ShowMessage(Sh.Cells[2, 2].Formula);
finally
Wb.Free;
end;
end;
ref özniteliği bir dekorasyon değil bir kapıdır. Koordinatları master'ın uygulanabilir aralığının dışına düşen bir takipçi genişletilmez, çünkü dosya o zaman grubun desteklemediği bir iddiada bulunuyor demektir. Aynı şekilde, bir kaydırma bir referansı satır birin üstüne ya da A sütununun soluna itmek üzereyken, HotXLS o token için sessizce kelepçelemek yerine #REF! yayınlar; bu, aynı düzenleme için Excel'in kendisinin üreteceği şeydir. Bu çeviri, satır eklediğinizde ya da sildiğinizde gerçekleşen referans yeniden yazımına yakın bir kuzendir ama aynı şey değildir. O yolun, bir düzenlemenin bir aralığın içinden geçtiğinde ne yaptığına dair kendi kuralları vardır ve satır ekleme ve silme sırasında formül referans ayarlaması üzerine yazıda ayrı olarak anlatılmıştır. Shared genişletme daha basittir: bilinen bir çapadan saf bir ofsettir, bir kez, ayrıştırma zamanında uygulanır
Kaydırıcının kapsaması gereken referans şekilleri hangileridir?
Hepsi, yoksa genişletme kılık değiştirmiş bir veri-kaybı hatasıdır. Yalnızca A1 ve A1:B2'yi anlayan saf bir kaydırıcı, daha egzotik biçimleri bozar ya da düşürür ve gerçek çalışma kitapları bunlarla doludur. HotXLS shared-formula çevirmeni, neyi taşıyacağına karar vermeden önce tüm A1 ailesini tanır. [Book.xlsx]Sheet1!A1 gibi harici çalışma kitabı referansları ve Sheet1:Sheet3!A1 gibi 3D referanslar, sondaki hücre referansı kayarken öneklerini bozulmadan korur. Tırnaklı sayfa isimleri hayatta kalır, sayfanın kelimenin tam anlamıyla A1 adını taşıdığı kötü durum dahil, bu yüzden 'A1'!A1 yalnızca ünlem işaretinden sonraki kısmı kaydırır. Tüm-sütun A:A, yalnızca sütun boyutunu hareket ettirir ve başka hiçbir şeyi; tüm-satır 1:1, yalnızca satır boyutunu hareket ettirir ve başka hiçbir şeyi; $A:$A hiç hareket etmez. Table[A1] gibi yapılandırılmış tablo referansları dokunulmadan bırakılır, çünkü köşeli parantez içindeki kısım bir koordinat değil bir sütun ismidir
// One master, expanded two columns to the right and zero rows down.
// Master D1: A1+A:A+$A:$A
// F1 : C1+C:C+$A:$A
//
// One master, expanded three rows down and zero columns across.
// Master A1: B1+$C$1+"A1"+A:A+1:1+'Data'!A1+LOG10(A1)+Table[A1]+'A1'!A1
// A3 : B3+$C$1+"A1"+A:A+3:3+'Data'!A3+LOG10(A3)+Table[A1]+'A1'!A3
//
// Note what did NOT move in the second line: the absolute $C$1, the
// string literal "A1", the whole column A:A under a pure row delta,
// the function name LOG10, and the structured reference Table[A1]
Fonksiyon isimleri burada sessiz tuzaktır. Harflerin ardından rakamları alan bir token tarayıcısı, bir satır aşağıda LOG10'u seve seve LOG11'e yeniden yazar. HotXLS, aday bir token'dan önce ve sonra bir referans sınırı gerektirir, bu yüzden bir harf, rakam, alt çizgi, nokta ya da açılış parantezine devam eden bir tanımlayıcı bir hücre referansı değildir. Diğer notasyon ailesinde çalışıyorsanız, aynı sınır sorunu farklı biçimde ortaya çıkar ve R1C1 notasyonu yazısı iki modelin nerede ayrıştığını kapsar
Kendini-kapatan bir f elemanı bir sonraki değeri neden yutar?
Çünkü kendini-kapatan bir eleman hiçbir end-element olayı üretmez. Bu, tüm özellikteki en pahalı tek hatadır ve herhangi belirli bir XML ayrıştırıcısına özgü değildir. TXMLReader'da, <f t="shared" si="4"/>, IsEmptyElement True olarak ayarlanmış tam olarak bir Element olayı yükseltir ve eşleşen EndElement'ı asla yükseltmez. Formül-yakalama durumunu yalnızca EndElement'te kapatan bir ayrıştırıcı bu yüzden formülün içinde kalır ve gördüğü bir sonraki metin, <v> içindeki önbelleklenmiş sonuç, formül tamponuna eklenir. Daha kötüsü, durum hücre sınırından sağ çıkar, bu yüzden gerçek bir <f>'ye sahip bir sonraki hücrenin formül metni önceki hücre tarafından soğurulur. Düzeltme, IsEmptyElement True olduğunda formül durumunu Element olayının kendisinde bitirmek ve beklemek yerine tüm takipçi çözümlemesini orada çalıştırmaktır. Bu, boş elemanı işleyen dalın içinde t, si, ref, aca ve ca'yı özniteliklerden okumak, shared genişletmeyi uygulamak, yeniden hesaplama özniteliklerini hücreye yazmak ve shared durumunu temizlemek anlamına gelir. Biçimin her iki yazımına da izin verdiğini unutmayın, <f t="shared" si="4"/> ve <f t="shared" si="4"></f>, ve ikincisi gerçekten bir EndElement yükseltir. Doğru bir okuyucu ikisini de aynı şekilde işlemek zorundadır, bu yüzden HotXLS her iki yazımı da aynı regresyon dosyasında kapsar
Seyrek, sırasız si değerleri ve bekleyen kuyruk
si özniteliği, kontrol ettiğiniz bir dizi konumu değil, dosya tarafından sağlanan işaretsiz bir tamsayıdır. Şemada hiçbir şey shared indekslerin yoğun olmasını, sıfırdan başlamasını ya da artan sırada görünmesini gerektirmez ve hiçbir şey düşman ya da basitçe garip bir dosyanın ilk hücrede si="4294967290" kullanmasını engellemez. En büyük gözlemlenen si'den bir arama dizisini boyutlandırmak bu yüzden bir optimizasyon değil bir bellek-tüketme ilkelidir. HotXLS, çalışma kitabı-açma yolunu bunun yerine sıralanmış seyrek bir tabloda tutar: shared gruplar, sıralanmış bir TStringList'te tamsayı anahtarları altında kaydedilir; bu, aramanın gerçekte var olan grup sayısına göre bir ikili arama yapmasını sağlar, indekslerin sayısal büyüklüğüyle hiçbir ilişkisi olmadan. Sıra sorunun ikinci yarısıdır. Bir master normalde takipçilerinden belge sırasında önce gelir ama bu bir kural değil bir gelenektir, bu yüzden ayrıştırıldığı anda si'sini çözemeyen herhangi bir takipçi bekleyen bir kuyruğa girer. Sayfa bittiğinde, kuyruk artık tamamlanmış tabloya karşı yeniden oynatılır ve geç master'lar yetimlerini çözer. Hiçbir zaman bir master bulamayan hücreler boş bir formül tutar; bu, hiç tanımlamadığı bir gruba referans veren bir dosya için dürüst sonuçtur
Çalışma kitabını yüklemeden shared formülleri genişletmek
Streaming okuyucular çok daha sıkı bir bellek bütçesi altında aynı gereksinimle karşılaşır ve bunu çalışma sayfası-yerel bir tabloyla çözerler. TXLSDirectReader ve TXLSRowCursor, sınırlı-bellek ve projeksiyon davranışlarını korurken takipçileri eksiksiz hücre-başına formüllere genişletir, bu yüzden 300 MB'lık bir sayfa üzerinden ileri-yönlü tek geçiş hâlâ size gerçek formül metni verir
var
Reader: TXLSDirectReader;
Cursor: TXLSRowCursor;
begin
// Projection: only rows 2..3, only column A. The master lives in row 1,
// outside the projection, and is still parsed so the followers resolve
Reader:= TXLSDirectReader.Create;
try
Reader.FirstRow:= 2;
Reader.LastRow:= 3;
Reader.IncludeColumn(1);
Reader.OnCell:= HandleCell; // Cell.Formula is fully expanded here
Reader.ReadFile(FileName);
finally
Reader.Free;
end;
// Forward-only row traversal, same expansion
Cursor:= TXLSRowCursor.Create;
try
Cursor.Open(FileName);
if Cursor.FindFirst then
repeat
if Cursor.CellCount > 0 then
WriteLn(Cursor.RowIndex, ': ', Cursor.Cells[0].Formula);
until not Cursor.FindNext;
finally
Cursor.Free;
end;
end;
Bu tasarımdan iki kısıt ortaya çıkar. Birincisi, projeksiyon master'ı asla atlayamaz. FirstRow ve LastRow ile kurulan bir satır filtresi ya da IncludeColumn ile oluşturulan bir sütun filtresi, master hücresini callback'inize yayınlamayı atlayabilir, ama ayrıştırıcı yine de onun si'sini, çapa koordinatlarını, uygulanabilir aralığını ve formül metnini kaydetmek zorundadır, aksi takdirde projeksiyon içindeki her takipçi hiçbir şeye çözülür. Yalnızca takipçi-tarafı iş, kaydırma ve değer çözme, atlamak için güvenlidir. İkincisi, tablo çalışma sayfası başınadır ve yaşam döngüsü açıkça yönetilmelidir: TXLSRowCursor, bir sayfa geçişi süresince bir örnek tutar ve yeniden başlatmada, sayfa değişiminde, dosya sonunda, exception'da ve kapatmada temizler, bu yüzden sayfa birde tanımlanan bir grup asla sayfa ikiye sızamaz. Streaming yolu sıcak bir döngü olduğundan, hücre başına bir tamsayı-dize dönüşümünden kaçınan açık-adresleme bir tamsayı hash'i kullanır, sıralanmış dize tablosu yerine
Kaydetmede ne olur ve sınırlar nerede
Bir takipçi genişletildikten sonra sıradan bir formüldür ve HotXLS bunu t="shared" ve si olmadan bağımsız bir <f> elemanı olarak geri yazar. Round trip kararlıdır ve önbelleklenmiş <v> sonuçları hayatta kalır, ama çıktı, yoğun biçimde shared bir sayfa için girdiden daha büyüktür ve Excel'in oluşturduğu gruplama kaydetmede yeniden inşa edilmez. Shared grupların bayt seviyesi sadakati sizin için her hücrede gerçek formül metnine sahip olmaktan daha önemliyse, kabul ettiğiniz takas budur. XLS tarafı bu arada farklıdır: BIFF8 SHRFMLA kaydının kendi kodlaması ve kendi yazıcısı vardır, çalışma kitabında bir paylaşılan-grup anahtarıyla
<f> elemanını paylaşmalarına rağmen açıkça shared formül olmayan iki ilgili şey vardır. Eski CSE dizi formülleri, çapalanmış aralığı kapsayan bir ref ile t="array" kullanır ve dinamik diziler aynı t="array" yazımını kullanır ama cellMetadata üzerinden bir XLDAPR kaydına zincirlenen bir cm özniteliğiyle tanımlanır. Bir dinamik-dizi taşma hücresini shared ya da CSE takipçisi olarak ele almak gerçek bir doğruluk hatasıdır ve ayrım dinamik dizi ve taşma formülleri üzerine yazıda ele alınmıştır. Üç durumu, tesadüfen bir etiket ismini paylaşan üç ayrıştırıcı olarak okuyun, kod dürüst kalır
Shared-formula genişletme, streaming okuyucular ve burada anlatılan referans çevirmen, Delphi ve C++Builder için HotXLS Excel component'in bir parçası olarak sunulur; ürün sayfası, yukarıda kullanılan projeksiyon özellikleri dahil tam formül ve direct-read API referansını içerir