Teknik Makale

Delphi'de HotXLS Çalışma Kitapları Arası Kopyalama ve Formül Yeniden Bağlama

HotXLS'in AddCopy metodu, bir çalışma sayfasını bir Excel çalışma kitabından diğerine, o sayfadaki her formülü A1 stili metne derlemesini geri alarak (decompile) ve metni hedef çalışma kitabı içinde yeniden derleyerek kopyalar; derlenmiş formül ağacını doğrudan kopyalamak yerine, çünkü grafik serisi referansları, zengin metin yazı tipi indeksleri ve dış bağlantı numaralandırması her çalışma kitabı dosyası içinde bağımsız olarak atanır

Bu başarısızlık tam olarak beklediğiniz çalışma kitabında ortaya çıkar: her şube ofisinin raporundan bir sayfa çeken ve bunu bir özet dosyasına ekleyen bir ay sonu işi. Sonucu açın ve bir alt toplam grafiği tamamen farklı bir şubenin sayısını çizer, kaynakta kalın ve kırmızı olan bir not düz siyah metne geri döner ve bir zamanlar bir yandaş arama çalışma kitabından bir vergi oranı çeken bir formül şimdi kimsenin açıklayamadığı donmuş bir sayı gösterir. Burada hiçbir şey bir istisna fırlatmaz -dosya açılır, sayılar makul görünür ve hasar, biri yanına oturmuş yanlış başlıklı bir grafiği fark edene kadar orada durur

AddCopy neden derlenmiş formül ağacını basitçe kopyalayamaz?

AddCopy derlenmiş formül ağacını değişmeden taşıyamaz, çünkü derlenmiş bir BIFF formülü bağımsız metin değildir -bir token dizisidir ve bu tokenlerden birkaçı, yalnızca onları üreten çalışma kitabı içinde doğru çözümlenen küçük tam sayılardır. Sheet2!A1:A10 gibi bir 3B referans, derlendikten sonra Sheet2 gerçek adını taşımaz; BIFF spesifikasyonunun ixti dediği bir alan taşır (HotPDF... HotXLS aynı değeri kendi derlenmiş ağacında FExternID alan adı altında tutar), o çalışma kitabının özel EXTERNSHEET tablosuna bir indeks, o belirli çalışma kitabının sayfalarını ve dış kitaplarını kaydettiği sıraya göre numaralandırılmış. Token'ı, EXTERNSHEET tablosu farklı bir sırada kurulmuş bir çalışma kitabına değişmeden taşıyın ve indeks 3 artık Sheet2 anlamına gelmez -orada slot 3'ü işgal eden her ne sayfa varsa onu ifade eder ve Excel'in hatayı işaretlemesinin hiçbir yolu yoktur, çünkü dosya formatı açısından formül mükemmel şekilde iyi biçimlendirilmiştir. Bu, tam olarak TXLSWorksheets.AddCopy'nin var olma nedeni olan başarısızlıktır: Delphi veya C++Builder kodunda her iki çalışma kitabının kendi sayfa koleksiyonundan çağrılan bu metot, bir çalışma sayfasını -hücre değerleri, formatlar, formüller, grafikler, yorumlar, birleştirmeler, sayfa yapısı ve daha fazlasını- üzerinde çağırdığınız çalışma kitabı olabilecek veya olmayabilecek bir kaynak çalışma kitabından kopyalar ve sonucu seçtiğiniz bir adla veya orijinalin belirsizliği giderilmiş bir kopyasıyla hedefe ekler

var
  Summary, Branch: IXLSWorkbook;   // interface-counted: do not Free
begin
  Summary := TXLSWorkbook.Create;
  Branch := TXLSWorkbook.Create;
  Branch.Open('branch-east.xls');

  // Appends a copy of Branch's first sheet onto Summary, renamed to
  // stay unique inside the destination workbook
  Summary.Sheets.AddCopy(Branch.Sheets[1], 'East Detail');
  Summary.SaveAs('consolidated.xls');
end;

Çözüm: metne çöz, hedefte yeniden derle

HotXLS indeksleme sorununu, derlenmiş ağacın kendisinin hiçbir zaman çalışma kitabı sınırını geçmesine izin vermeyerek çözer. Çalışma kitapları arası bir kopyada her formül hücresi için, AddCopy kaynak formülü, bir kullanıcının Excel'in formül çubuğunda göreceği aynı A1 stili metne çözer, ardından bu metni hedef çalışma kitabına verir; o da bunu kendi tablolarını sıfırdan kullanarak yeniden bir ağaca ayrıştırır -o noktada Data!D2:D100 gibi sayfa nitelikli bir referans yalnızca bir dizedir ve bir dize herhangi bir çalışma kitabında aynı anlama gelir; bu yüzden hedefte zaten Data adlı bir sayfa varsa, referans hiçbir indeks çevirisi olmadan doğru çözülür, çünkü çevrilecek ham bir indeks hiç uçuşta olmamıştır. HotXLS bu gidiş-dönüş için yalnızca gerektiğinde öder: aynı çalışma kitabı içinde bir sayfayı kopyalamak, derlenmiş ağacın basitçe bellekte çoğaltıldığı daha ucuz bir yol izler, çünkü içindeki her indeks kalacağı yerde zaten geçerlidir ve metin çevresi yalnızca AddCopy kaynağın ve hedefin gerçekten farklı çalışma kitabı örnekleri olduğunu tespit ettiğinde çalışır. Bu yeniden yazımın ne olmadığını da kesin olarak belirtmekte fayda var. Bunun, tek bir sayfa içinde satır eklediğinizde veya sildiğinizde çalışan satır ve sütun kaydırmasıyla hiçbir ilgisi yoktur; bu, bir tamamlayıcı makalenin ayrıntılı olarak ele aldığı bir konudur -o motor, tek bir çalışma kitabı içinde birkaç satır yukarı veya aşağı hareket eden hücreleri takip etmek için A1 metnini yerinde yeniden yazar, bu motor ise bir formül onu derleyen çalışma kitabından tamamen ayrıldığında çalışır; burada taşınan satırlar sorun değildir, çalışma kitabına özel numaralandırma sorundur

// Conceptually, this is what AddCopy does for each formula cell: turn
// the compiled tree back into text using the source workbook's own
// tables, then let the destination workbook parse that text back into
// a tree using its own tables, from scratch
FormulaText := SourceBook.GetUnCompiledFormula(SourceFormula, Row, Col, SourceSheetID);
DestFormula := DestBook.GetCompiledFormula(FormulaText, DestSheetID);

Ya hedefte o sayfa veya o ad henüz yoksa?

AddCopy'nin yeniden derlemesi yalnızca hedef çalışma kitabı formül metninin referans verdiği her şeye zaten sahip olduğunda başarılı olur ve pratikte ortaya çıkan iki boşluk, bu toplu iş içinde henüz kopyalanmamış aynı adlı bir sayfa ve hedefte hiç var olmamış çalışma kitabı kapsamlı tanımlı bir addır. HotXLS, bir sayfa kopyası sırasında yeniden derleme başarısız olduğunda bir istisna fırlatmaz -hücrenin Value ataması bunun yerine sessizce formül metnini düz bir dize olarak saklar; sessiz değil kasıtlı, incelenebilir bir başarısızlık modu, çünkü beklenmedik şekilde hesaplanmış bir sayı yerine =SUM(Q1!B2:B12) gibi gerçek metin gösteren bir formül hücresi, kopyanın yukarısında bir şeyin çözülmediğinin işaretidir. Vazgeçmeden önce, AddCopy bir onarım dener: başarısız formülün sözdizimi ağacını dolaşır, formülün dokunduğu her tanımlı ad kimliğini toplar ve kaynakta olup hedefte henüz olmayan her çalışma kitabı kapsamlı ad için, adı karşıya kopyalar ve aynı metni ikinci kez yeniden derler. Sayfa kapsamlı adlar, bu onarımın düzeltebileceğinin dışında kalır, çünkü kaynak çalışma kitabının yalnızca bir sayfasındaki formüllere görünen bir adın geçebileceği eşdeğer bir slot yoktur ve zaten aynı yazımla bir ad taşıyan bir hedef, üzerine yazılmak yerine dokunulmadan bırakılır; çağıranın kasıtlı olarak önceden oluşturduğu bir adın onurlandırılmasını istediği varsayımıyla. Tek bir çalışma kitabı içinde, sayfalar arası bir formülün ad araması sayfa kapsamından çalışma kitabı kapsamına otomatik olarak yükselir; bu, HotXLS'in tanımlı adlar ve sayfalar arası formüller makalesinin ele aldığı mekanizmadır; gerçek bir çalışma kitabı sınırını geçmek bu güvenlik ağını tamamen kaldırır ve bir ad ya kasıtlı olarak karşıya taşınmalıdır ya da ona bağlı formül metne düşer

Grafik serisi referansları aynı düzeltmeye ihtiyaç duyar, ama farklı bir kod yolundan

Bir hücre aralığını çizen bir HotXLS grafik serisi, tam olarak sıradan bir hücre formülüyle aynı numaralandırma sorununu yaşar, çünkü bir grafiğin veri aralığı referansı da derlenmiş bir formül token akışıdır -BIFF spesifikasyonu onu taşıyan kaydı BRAI olarak adlandırır ([MS-XLS] bölüm 2.4.51)- ama AddCopy bunu normal grafik yükleme yolunu yeniden kullanarak düzeltemez, çünkü o yol tam olarak hatayı yaratan şeydir. Bir grafik kaydı, bir dosyayı açmanın sıradan seyrinde diskten ayrıştırıldığında, formül ağacı ham baytları ayrıştırmayı yapan her ne hesap makinesi örneği varsa onun üzerinden çevirerek kurulur; bunun yerine bir kaynak grafiğin ham BRAI baytlarını hedef çalışma kitabının kendi sıradan kayıt yükleyicisi üzerinden besleyin ve bu baytların içine gömülü ixti, hedefin EXTERNSHEET tablosuna karşı çözümlenir; bu yüzden seri sessizce orada o slotu işgal eden her ne sayfa varsa ona işaret eder -bir hücrenin derlenmiş ağacını değişmeden kopyalamakla aynı sınıf hata, yalnızca fark edilmesi daha zor çünkü kimse grafik serisi formüllerini hücre formüllerini okuduğu şekilde okumaz. HotXLS bu tuzaktan bunun yerine özel bir klonlama yoluyla kaçınır: TXLSCustomChart.AssignFrom, her grafik kaydının kendi formül olmayan başlık baytlarını olduğu gibi kopyalar, ardından ekli aralığı sıradan hücreler için kullanılan aynı çöz-ve-yeniden-derle ilkelini kullanarak yeniden kurar; bu yüzden yeni ağaç, sonradan yeniden yorumlanmak yerine sıfırdan hedefin EXTERNSHEET tablosuna karşı inşa edilir

Aynı numaralandırma sorunu, seferinde bir yazı tipi indeksi

Bir grafik veya zengin metin hücresi içindeki her çalışma kitabına özel sayı bir formül değildir ve bir yazı tipi indeksi bu sorunun minyatür aynı sınıfıdır. Zengin metin çalışmaları, bir başlık veya eksen yazı tipi taşıyan iki grafik kayıt türüyle birlikte, bir yazı tipi referansını sahip olan çalışma kitabının kendi yazı tipi tablosuna ham bir tam sayı indeksi olarak saklar ve bu indeks farklı bir çalışma kitabının tablosunda hiçbir anlam ifade etmez -orada tamamen farklı bir yazı tipi, boyut veya renge aynı kolaylıkla işaret edebilir. HotXLS bunu sayıya göre değil değere göre çözer: kaynak tablodaki o indekste gerçek yazı tipi özniteliklerini arar, hedefin yazı tipi tablosunda eşleşen bir girdi bulur veya oluşturur ve saklanan indeksi o yeni slotu işaret edecek şekilde yeniden yazar. Bir format tuhaflığı aramanın kendisini biraz zahmetli kılar -dosyadaki indeks slot 4'ü atlar, [MS-XLS] bölüm 2.5.339'un belgelediği bir numaralandırma boşluğu; bu yüzden kod, yazı tiplerini karşılaştırmadan önce indeksi bir aşağı kaydırmak ve sonucu yazmadan önce bir yukarı kaydırmak zorundadır

// The file-numbered font index skips slot 4 (MS-XLS section 2.5.339);
// shift into the in-memory slot, migrate the font by value if the
// destination differs, then shift back before writing the result
if Ifnt >= 5 then
  Dec(Ifnt);
if DestFonts.Key[Ifnt] <> SourceFonts.Key[Ifnt] then
  Ifnt := DestFonts.SetKey(0, SourceFonts.Key[Ifnt]);
if Ifnt >= 4 then
  Inc(Ifnt);

AddCopy'yi hiç çağırmadan önce çalışma kitabının dışına işaret eden bir formüle ne olur?

AddCopy'yi hiç çağırmadan önce üçüncü bir çalışma kitabına uzanan bir formül, metin gidiş-dönüşünün taşıyamadığı tek durumdur, çünkü HotXLS'in kendi formül-metin çözücüsü kasıtlı olarak bir dış referans için [Book]Sheet! köşeli parantez metnini sentezlemez ve diğer uçtaki derleyici de bu sözdizimini girdi olarak kabul etmez -bu yüzden bu tek durum, metne hiç dokunmayan ikinci bir mekanizma üzerinden çalışır. Yukarıda açıklanan ad taşıma onarımı bir hücreyi yine de bir dize olarak bıraktığında ve kaynak çalışma kitabının gerçek bir dosya adı olduğunda, AddCopy strateji değiştirir: metnini değil derlenmiş formül ağacının kendisini derinlemesine kopyalar, ardından kopyayı düğüm düğüm dolaşan özel bir yeniden bağlama geçişine, RebindExternRefsInTree'ye verir. Bulduğu her aralık referansı için, o geçiş kaynağın EXTERNSHEET girdisini bir çift sayfa adına geri çözer ve hedefin kendi dış referans tablolarında eşdeğer bir girdiyi kaydeder veya yeniden kullanır; hedef daha önce hiç o kaynak dosyaya referans vermemişse yepyeni bir dış çalışma kitabı bağlantısı oluşturur

Çalışma kitabına özel numaralandırma sorununun en gerçek olduğu yer burasıdır, çünkü bir dış referans token'ı üç ayrı koordinatı tek bir alana paketler ve her biri onu yazan çalışma kitabına özeldir: hangi dış çalışma kitabı, hedefin kendi dış kitaplar listesinde o çalışma kitabının onları kaydettiği sırayla atanmış bir slot; o dış çalışma kitabının kendi sayfa listesi içindeki hangi sayfa, özellikle o dış kitaba kapsamlanmış 1 tabanlı bir indeks olarak saklanmış, hedefin kendi dahili sayfa kimliklerinden tamamen farklı bir numaralandırma alanı; ve hücre aralığının kendisi, hiçbir çeviri gerektirmeyen düz satır ve sütun koordinatları, çünkü hiçbir zaman çalışma kitabına göreli olmamışlardır. İlk ikisinden birini yanlış alın ve Excel dosyayı yine de açar, yine de bir formül gösterir ve onu şikayet etmeden yanlış dış hücrelere karşı değerlendirir. Bir tür düğüm bu ağaç düzeyindeki yeniden bağlamayı bile yener: bir tanımlı ada referans, tam olarak bir sayfa indeksinin kendi EXTERNSHEET'ine özel olduğu şekilde kendi çalışma kitabının özel ad tablosuna bir indekstir, mevcut hiçbir ağaç düzeyinde onarım yoktur -yeniden bağlama dolaşımı ağacın herhangi bir yerinde bir ad referansıyla karşılaştığı an, kısmen doğru bir formülü yazmak yerine formülün tamamından vazgeçer. Yeniden bağlama başarılı olsa bile, hedef hücre yeni hesaplanmış bir sayı göstermez; kopya zamanında kaynak hücrenin zaten tuttuğu değeri gösterir, Excel'in kendisinin siz bağlantıları açıkça yenileyene kadar herhangi bir dış referansın bilinen son değerini önbelleğe aldığı aynı şekilde önbelleğe alınmış bir slotta tutulur ki bu doğru varsayılandır, çünkü başka bir dosyaya canlı bir bağlantı üzerinden yeniden hesaplama, her açılışta değil, bilinçli olarak bir kez tetiklemek istediğiniz tam olarak bu tür bir işlemdir

Bu tasarım size neye mal olur

AddCopy'nin çöz-ve-yeniden-derle makinesi bedava değildir ve maliyet, büyük bir konsolidasyon işini betiklemenizden sonra değil önce planlamaya değer. Aynı çalışma kitabı içinde bir sayfayı kopyalamak ucuz yolu izler, derlenmiş ağacın düz bir bellek içi çoğaltmasını, çünkü içindeki her indeks kaldığı çalışma kitabında zaten geçerlidir; çalışma kitapları arası bir kopya ise bunun yerine her formül hücresinde gerçek bir ayrıştırma için öder, metne çöz ve sonra o metni sıfırdan tekrar derle; ve fark birkaç düzine formüllü bir sayfada ölçmeye değmezken, bir toplu iş içinde düzinelerce sayfadan biri olarak kopyalanan on binlerce formül hücreli bir kaynak çalışma kitabı, çevresindeki dosya G/Ç'sini değil yeniden derlemenin çalışma süresine hakim olmasını beklemelidir. Kopyalama sırası, hızın ötesinde ikinci bir nedenle önemlidir: AddCopy'nin bu toplu işte henüz ulaşmadığı bir sayfaya referans veren bir formül, gerçekten var olmayan bir sayfaya referans veren bir formülle aynı nedenle yeniden derlemesini başaramaz; bu yüzden B sayfasını, ona bağlı A sayfası formülünden önce kopyalayan bir iş, o formülün tam olarak yukarıda açıklandığı gibi bozulduğunu görecektir, dize metni veya az önce geldiği kaynak dosyaya tam geri işaret eden bir dış bağlantı yedeği. Ve bir konsolidasyon toplu işindeki her kaynak çalışma kitabı genellikle bağımsız olarak yazıldığından, hiçbir tek kaynak dosyanın sizi asla uyaramayacağı tek başarısızlık modunu açıkça test etmeye değer -her biri bir eşdeğer şubenin sayılarını toplayan beş şube çalışma kitabı, hiçbir tek kaynak dosya hiçbir zaman birini içermeden özet çalışma kitabının içinde gerçek bir dairesel referansa birleşebilir; her sayfa aynı yere indiğinde ve yeniden hesaplama birleşik küme üzerinde çalıştığında ancak var olan bir döngü

Çalışma kitapları arası çalışma sayfası kopyalama, Delphi ve C++Builder için HotXLS Delphi Excel Bileşeni'nde AddCopy'nin standart davranışı olarak gönderilir; ürün sayfası, burada açıklanan grafik, zengin metin ve dış referans davranışı dahil tam çalışma sayfası ve çalışma kitabı API referansını taşır