Artikel Teknis

Round-Trip XLSX Lossless di Delphi: Tema, extLst, calcChain

HotXLS, pustaka Excel asli untuk Delphi dan C++Builder, dibuat untuk proses bolak-balik (round-trip) XLSX lossless: buka buku kerja, ubah satu sel, simpan, dan tema khusus pelanggan, blok ekstensi extLst asing, serta rantai perhitungan semuanya tetap bertahan. Tiga mekanisme membuat hal itu berfungsi — penyimpanan cache verbatim dari xl/theme/theme1.xml, penyusunan ulang (re-serialization) berbasis peristiwa dari blok <ext> yang tidak dikenal, and xl/calcChain.xml baru yang valid secara spesifikasi pada setiap penyimpanan buku kerja formula

Skenario yang memotivasi ketiganya sangat umum terjadi. Layanan penagihan memuat templat yang dirancang pelanggan di Excel — tema warna perusahaan, sparklines di kolom KPI, aturan format bersyarat yang ditambahkan oleh versi Excel yang lebih baru — menulis satu total faktur ke dalam sel B3, dan menyimpan. Pelanggan membuka hasilnya dan warna merek telah kembali ke biru Office standar, sparklines hilang, dan Excel menawarkan untuk "memperbaiki" file tersebut. Tidak ada bagian dalam kode yang menyentuh fitur-fitur tersebut. Pustaka melakukannya, hanya dengan menyimpan

Mengapa file Excel kehilangan pemformatan setelah pengeditan oleh pustaka?

File Excel kehilangan pemformatan setelah pengeditan oleh pustaka karena sebagian besar pustaka tidak mengedit file — mereka membangunnya kembali. Paket .xlsx adalah file ZIP dari bagian-bagian XML: xl/workbook.xml, satu xl/worksheets/sheetN.xml per lembar, xl/styles.xml, xl/theme/theme1.xml, xl/calcChain.xml, dan banyak lagi. Pustaka tipikal mengurai bagian-bagian tersebut ke dalam model objek saat dibuka dan menghasilkan kembali setiap bagian dari model tersebut saat disimpan. Fitur apa pun yang tidak diwakili oleh model tersebut — tema yang tidak pernah diuraikan, blok ekstensi dari Excel yang lebih baru — tidak memiliki tempat untuk tinggal di memori, sehingga bagian yang dihasilkan kembali menghilangkannya secara senyap

ECMA-376 mengantisipasi setengah dari masalah ini. SpreadsheetML mendefinisikan extLst (ECMA-376 Bagian 1, "Future Feature Data Storage Area", §18.2.10 untuk elemen tingkat buku kerja) sebagai titik ekstensi yang ditentukan: produsen yang lebih baru menempatkan fitur di sana, masing-masing dibungkus dalam elemen <ext> yang membawa atribut uri yang mengidentifikasi fitur tersebut, dan konsumen yang lebih lama diharapkan mempertahankan apa yang tidak mereka pahami. Sparklines, slicers, dan jenis format bersyarat yang lebih baru semuanya berjalan dengan cara ini. Pustaka yang menghilangkan blok <ext> yang tidak dikenal oleh karena itu tidak hanya sekadar lossy — ia melanggar kontrak kompatibilitas maju (forward-compatibility) yang dirancang untuk format tersebut. Pertanyaan yang diajukan kepada pustaka spreadsheet apa pun yang Anda evaluasi sangat jelas: jika saya mengubah satu sel, apa lagi yang berubah

Bagaimana HotXLS mempertahankan tema khusus bita demi bita?

HotXLS mempertahankan tema buku kerja dengan menyimpan bita asli xl/theme/theme1.xml di cache pada saat dibuka dan menulisnya kembali secara verbatim pada saat disimpan. Bagian tema (ECMA-376 Bagian 1, §14.2.7) adalah DrawingML, bukan SpreadsheetML — skema warna, skema font, skema format — dan mesin spreadsheet tidak memiliki alasan untuk memodelkannya secara mendalam. Versi HotXLS sebelumnya menghasilkan tema Office tetap pada setiap penyimpanan, yang merupakan kegagalan "warna merek kembali ke semula" di atas; sejak v2.89.46, tema paket yang dibuka disimpan secara mentah dan dipancarkan kembali tanpa disentuh, dan tema Office bawaan hanya dihasilkan untuk buku kerja yang dibuat dari awal. Bita mentah adalah jaminan fidelitas terkuat yang dimungkinkan: tanpa penguraian, tanpa serialisasi ulang, tanpa kemungkinan pergeseran (drift)

Salinan verbatim secara sengaja mengalahkan akses tema terprogram. TXLSXWorkbook mengekspos ThemeMajorFont dan ThemeMinorFont sehingga Anda dapat memilih jenis huruf judul dan isi untuk buku kerja baru, tetapi ketika tema verbatim ditangkap saat dibuka, penyetel tersebut tidak memiliki efek pada file yang disimpan — proses bolak-balik (round-trip) menjadi prioritas. Jika Anda benar-benar perlu mengubah tema buku kerja yang ada, itu adalah sinyal untuk mengedit templat di Excel itu sendiri daripada melalui API yang berorientasi data. Kasus sehari-hari sama sekali tidak memerlukan API:

var
  Book: TXLSXWorkbook;
begin
  Book := TXLSXWorkbook.Create;
  try
    Book.Open('branded-invoice.xlsx');
    Book.Sheets[0].Cells[3, 2].Value := 42750.00;  // satu pengeditan
    Book.SaveAs('branded-invoice-out.xlsx');
    // theme1.xml di keluaran adalah identik bita dengan masukan
  finally
    Book.Free;
  end;
end;

Apa yang terjadi pada blok extLst yang tidak dikenal saat disimpan?

HotXLS menangkap setiap elemen <ext> tingkat lembar kerja yang tidak dimodelkan secara asli dan memutarnya kembali ke dalam extLst lembar kerja yang disimpan, sehingga fitur yang ditulis oleh versi Excel yang lebih baru tetap bertahan selama proses bolak-balik (round-trip). Sejak v2.131.0, fragmen yang ditangkap dapat dilihat melalui properti read-only RawWorksheetExts, sebuah TStringList pada setiap lembar kerja XLSX, yang membuat jaminan tersebut dapat diaudit dari kode pengujian alih-alih sekadar keyakinan:

var
  Book: TXLSXWorkbook;
  Sheet: TXLSXWorksheet;
  i: Integer;
begin
  Book := TXLSXWorkbook.Create;
  try
    Book.Open('from-newer-excel.xlsx');
    Sheet := Book.Sheets[0];
    WriteLn(Format('%d foreign ext block(s) captured',
      [Sheet.RawWorksheetExts.Count]));
    for i := 0 to Sheet.RawWorksheetExts.Count - 1 do
      WriteLn(Copy(Sheet.RawWorksheetExts[i], 1, 100)); // intip setiap uri
  finally
    Book.Free;
  end;
end;

Detail implementasi yang patut diketahui adalah bahwa penangkapan tersebut merupakan penyusunan ulang (re-serialization) tingkat peristiwa, bukan salinan bita mentah. Pembaca XML streaming HotXLS tidak mengekspos offset sumber, sehingga subpohon yang tidak dikenal dibangun kembali dari peristiwa Element, Text, dan EndElement saat mereka mengalir lewat. Pendekatan itu menyembunyikan satu jebakan klasik: elemen yang menutup sendiri seperti <a/> hanya memicu peristiwa Element yang ditandai kosong dan tidak pernah memicu EndElement, sehingga penghitung kedalaman apa pun yang berkurang hanya pada EndElement tidak akan pernah melihat subpohon tersebut ditutup. Tangani hal itu, dan fragmen yang dibangun kembali secara semantik setara dengan aslinya — tanda kutip atribut dan bentuk penutupan sendiri dinormalisasi, sehingga tidak identik secara bita, tetapi Excel membaca makna, bukan bita. Dua sifat dari keluaran Excel sendiri membuat pemutaran ulang aman: Excel mendeklarasikan atribut xmlns yang diperlukan pada elemen <ext> atau di dalamnya, sehingga setiap fragmen yang ditangkap mandiri secara namespace, dan kemandirian yang sama adalah alasan mengapa menduplikasi lembar kerja di dalam atau di seluruh buku kerja dapat membawa blok asing bersama dengan penetapan daftar string biasa

Menulis calcChain.xml agar Excel mempercayai formula Anda

HotXLS menulis xl/calcChain.xml (bagian Rantai Perhitungan, ECMA-376 Bagian 1, §12.3.1) setiap kali buku kerja yang disimpan mengandung formula, dan ia memilih di antara dua pengurutan. Jika grafik dependensi formula telah dibangun dan mutakhir — Anda memanggil Recalculate setelah pengeditan terakhir Anda — rantai dipancarkan dalam urutan topologis lengkap, dependensi sebelum dependen, dengan anggota referensi melingkar ditambahkan di bagian akhir. Jika tidak, sel dicantumkan dalam urutan dokumen. Keduanya benar: catatan implementasi Microsoft untuk format tersebut, [MS-XLSX], memperlakukan rantai perhitungan sebagai petunjuk yang diverifikasi dan diurutkan ulang oleh Excel selama pemuatan, sehingga daftar lengkap apa pun sah, dan HotXLS sengaja menolak untuk memaksakan pembangunan grafik di dalam SaveAs — konstruksi tepi bersifat kuadratik dalam jumlah sel, biaya tersembunyi yang tidak dapat diterima pada penyimpanan sejuta sel

Book.Open('model.xlsx');
Book.Sheets[0].Cells[10, 4].Formula := '=SUM(D2:D9)';
// Disimpan sekarang, calcChain.xml mencantumkan sel formula dalam urutan dokumen.
// Setelah Recalculate, grafik dependensi ada, sehingga penyimpanan yang sama
// memancarkan urutan topologis lengkap sebagai gantinya:
Book.Recalculate;
Book.SaveAs('model-out.xlsx');

Mengapa peduli tentang bagian yang diperlakukan Excel sebagai saran? Karena ketidakadaannya adalah sebuah sinyal. Beberapa konsumen — heuristik perbaikan, penampil pihak ketiga, alat diff — mengharapkan buku kerja formula membawa rantai perhitungan, dan pustaka yang secara senyap menghilangkan bagian tersebut saat disimpan menghasilkan file yang secara halus tidak seperti apa pun yang ditulis Excel. Memancarkan rantai yang valid menjaga keluaran tetap berada di dalam amplop dari apa yang telah diuji oleh ekosistem lainnya, yang merupakan inti dari rekayasa bolak-balik yang tenang dan tidak mencolok

Di mana proses bolak-balik (round-trip) lossless berakhir

Kejujuran lebih penting daripada kotak centang pemasaran di sini, sehingga batas-batasnya layak mendapatkan porsi yang sama. HotXLS tidak menyalin seluruh paket bita demi bita: XML lembar kerja, gaya, string bersama, dan bagian-bagian buku kerja dihasilkan kembali dari model yang diuraikan, sehingga keluaran secara semantik setia tetapi tidak identik secara biner — header lokal ZIP saja membawa stempel waktu DOS yang baru. Fragmen <ext> yang ditangkap kembali dalam keadaan dinormalisasi, seperti yang dijelaskan di atas. Pengabaian font tema terprogram diabaikan ketika tema verbatim ada. Dan jaring pelestarian memiliki jaring yang jelas: fitur yang dimodelkan HotXLS secara native (misalnya sparklines, diuraikan dan ditulis ulang alih-alih disalin secara buta) ditambah konten extLst asing ditambah bagian yang disimpan dalam cache secara verbatim. Bagian yang tidak dimodelkan maupun tidak berada di dalam titik ekstensi — katakanlah bagian kustom add-in yang eksotis — berada di luar tiga mekanisme yang dibahas artikel ini, jadi uji templat Anda yang sebenarnya alih-alih berasumsi

Pekerjaan pelestarian yang berdekatan melengkapi gambaran ini. Proyek VBA dan referensi buku kerja eksternal melewati penyimpanan dengan filosofi pertahankan-apa-yang-tidak-Anda-modelkan yang sama, dibahas dalam artikel pendamping tentang pelestarian VBA dan tautan eksternal, dan properti dokumen di docProps memiliki API baca-tulis mereka sendiri alih-alih dihilangkan secara senyap. Ketika Anda mengevaluasi pustaka spreadsheet apa pun, jalankan pengujian satu sel: buka buku kerja produksi yang kaya fitur, ubah satu nilai, simpan, dan bandingkan (diff) bagian-bagian yang di-unzip terhadap aslinya. Apa yang berubah di luar lembar yang Anda sentuh memberi tahu Anda lebih banyak tentang pustaka tersebut daripada matriks fitur apa pun

Mekanisme bolak-balik yang dijelaskan di sini — retensi tema verbatim sejak v2.89.46, penangkapan extLst asing, dan emisi calcChain.xml sejak v2.131.0 — dikirimkan dalam HotXLS Delphi Excel Component saat ini, yang halaman produknya mendokumentasikan rangkaian fitur baca-tulis XLSX lengkap untuk Delphi dan C++Builder