Artikel Teknis

Diff Dua Workbook Excel di Delphi dengan HotXLS

HotXLS membandingkan dua workbook melalui TXLSXWorkbookCompare, yang memasangkan worksheet berdasarkan nama, menelusuri cell terisi dari setiap pasangan, dan melaporkan apa yang berbeda sebagai daftar terstruktur rekaman perbedaan dan, jika diminta, sebagai satu baris yang mudah dibaca per perbedaan. Tidak ada instalasi Excel yang terlibat, dan perbandingan berjalan sepenuhnya pada model objek yang dimuat di Delphi atau C++Builder

Kebutuhan ini biasanya muncul saat pertama kali seseorang bertanya apa yang berubah. Sebuah workbook keuangan kembali dari peninjauan, ekspor malam hari diregenerasi setelah perubahan kode, atau dua departemen mengirimkan versi template yang sama. Membuka keduanya berdampingan berhasil untuk satu sheet dan gagal untuk dua puluh. Membandingkan berkas byte demi byte tidak menjawab apa pun, karena dua kali penyimpanan workbook yang sama berbeda dengan cara yang tidak dipedulikan siapa pun

Apa yang dihitung sebagai perbedaan?

Perbandingan melaporkan delapan jenis, dan kumpulannya sengaja dibuat kecil: sheet ditambahkan atau dihapus, cell terisi ditambahkan atau dihapus, cell yang value-nya berubah, cell yang formula-nya berubah, dan merged range ditambahkan atau dihapus. Semuanya dinyatakan terhadap workbook kiri sebagai baseline, sehingga item yang ditambahkan hanya ada di sebelah kanan dan item yang dihapus hanya di sebelah kiri

Sheet dipasangkan berdasarkan nama, bukan posisi. Karena itu, mengurutkan ulang worksheet tidak menghasilkan perbedaan apa pun, yang hampir selalu merupakan perilaku yang Anda inginkan: pengguna yang menyeret sebuah tab bukanlah perubahan data. Sheet yang hanya ada di satu sisi melaporkan satu entri level sheet alih-alih memperluas setiap cell terisi di dalamnya, yang menjaga laporan dua workbook yang secara struktural berbeda tetap mudah dibaca alih-alih menjadi ribuan baris panjangnya

Value atau formula, dan bagaimana masing-masing dibandingkan

Setiap cell menyumbangkan sebuah signature, dan aturannya sederhana: cell yang membawa formula dibandingkan berdasarkan teks formulanya dengan tanda sama dengan di depan, dan cell tanpa formula dibandingkan berdasarkan value-nya yang dikonversi ke teks. Perbedaan ini lebih penting daripada yang terlihat sekilas. Dua cell dapat memuat angka tampilan yang sama sementara satu adalah literal dan yang lain formula, dan memperlakukan keduanya sebagai setara akan menyembunyikan tepat edit yang paling layak ditangkap dalam workbook yang ditinjau

Ini juga berarti formula yang teksnya tidak berubah tidak melaporkan perbedaan meskipun hasil cache-nya berbeda, yang merupakan perilaku benar untuk membandingkan konten yang ditulis, dan perilaku salah jika Anda mencoba mendeteksi drift rekalkulasi. Untuk pertanyaan kedua itu, rekalkulasikan kedua workbook sebelum membandingkan, sehingga value yang Anda bandingkan adalah value yang benar-benar dihasilkan formula hari ini

Menjalankan perbandingan

Compare menerima dua workbook yang dimuat dan mengembalikan jumlah perbedaan yang ditemukan. Daftar perbedaan kemudian tersedia berdasarkan indeks, atau dapat dibuang ke TStrings mana pun:

uses
  lxHandleX, lxCompare;

var
  Left, Right: TXLSXWorkbook;
  Cmp: TXLSXWorkbookCompare;
  Lines: TStringList;
begin
  Left := TXLSXWorkbook.Create;
  Right := TXLSXWorkbook.Create;
  Cmp := TXLSXWorkbookCompare.Create;
  Lines := TStringList.Create;
  try
    if (Left.Open('baseline.xlsx') <> 1) or
       (Right.Open('reviewed.xlsx') <> 1) then
      Exit;

    if Cmp.Compare(Left, Right) = 0 then
      Writeln('workbooks are equivalent')
    else
    begin
      Cmp.Report(Lines);              // satu baris mudah dibaca per perbedaan
      Lines.SaveToFile('workbook-diff.txt');
      Writeln(Format('%d difference(s) written', [Cmp.Count]));
    end;
  finally
    Lines.Free;
    Cmp.Free;
    Right.Free;
    Left.Free;
  end;
end;

Satu baris yang dihasilkan Report berbunyi seperti value changed: Data!A2: 10 -> 99, yang sudah cukup bagi seorang reviewer dan cukup bagi sebuah commit message. Itu adalah permukaan yang menghadap manusia. Permukaan programatiknya adalah rekaman perbedaan itu sendiri, dan itulah yang digunakan ketika perbandingan menggerakkan sebuah keputusan alih-alih sebuah dokumen

Menggerakkan logika dari perbedaan terstruktur

Setiap perbedaan mengekspos jenisnya, nama sheet, baris dan kolom berbasis satu untuk entri level cell, referensi A1 untuk entri level merge, serta teks kiri dan kanan. Entri level sheet dan level merge melaporkan baris dan kolom sebagai nol, yang menjadi cara membedakannya tanpa memeriksa jenisnya:

var
  I: Integer;
  D: TlxCompareDiff;
  FormulaEdits: Integer;
begin
  FormulaEdits := 0;
  for I := 0 to Cmp.Count - 1 do
  begin
    D := Cmp.Diff(I);
    case D.Kind of
      lckFormulaChanged:
        begin
          Inc(FormulaEdits);
          Writeln(Format('%s R%dC%d: %s => %s',
            [D.Sheet, D.Row, D.Col, D.LeftText, D.RightText]));
        end;
      lckSheetAdded, lckSheetRemoved:
        Writeln(Format('structure: %s', [D.Describe]));
      lckMergeAdded, lckMergeRemoved:
        Writeln(Format('layout: %s at %s', [D.Describe, D.Ref]));
    end;
  end;

  // Kebijakan review yang hanya memblokir pada edit formula
  if FormulaEdits > 0 then
    raise Exception.CreateFmt(
      '%d formula change(s) need sign-off', [FormulaEdits]);
end;

Dua properti output layak diketahui sebelum Anda menulis assertion terhadapnya. Urutan entri level cell mengikuti urutan traversal internal dari cell store, sehingga pengujian harus ditulis dengan cara yang tidak bergantung pada urutan. Dan signature formula membawa tanda sama dengan-nya sendiri di depan, yang berarti string deskripsi yang dibangun lewat penggabungan dapat menampilkan == ganda; periksa nilai field alih-alih mem-parsing baris deskriptif ketika hasilnya menggerakkan logika

Di mana diff workbook memberikan manfaat

Tiga kegunaan membenarkan fitur ini dengan sendirinya. Pengujian regresi generator laporan: simpan workbook yang diketahui baik, regenerasi, bandingkan, dan gagalkan build pada perbedaan tak terduga apa pun. Peninjauan perubahan: berikan reviewer laporan yang mudah dibaca alih-alih dua berkas. Dan verifikasi migrasi: setelah mengonversi sekumpulan workbook lawas, bandingkan setiap hasil dengan sumbernya untuk membuktikan tidak ada yang hilang

Kasus ketiga itu berpasangan secara alami dengan pass inventarisasi dan audit yang dijelaskan dalam workbench audit dan konversi workbook, di mana menghitung isi workbook terjadi sebelum konversi dan perbandingan terjadi sesudahnya. Jika perbedaan Anda mengelompok di sekitar baris yang disisipkan, aturan penulisan ulang referensi dalam penyesuaian referensi formula pada insert dan delete menjelaskan mengapa formula yang tampak tidak berubah dilaporkan sebagai berubah

Batasan, dinyatakan secara terus terang

Perbandingan mencakup value, formula, merge, dan keberadaan sheet. Ia tidak membandingkan format angka, font, fill, aturan conditional formatting, data validation, chart, gambar, atau defined name. Cell yang value-nya identik tetapi formatnya berubah dari General ke Currency tidak melaporkan perbedaan, yang benar untuk perbandingan data dan tidak memadai untuk peninjauan pemformatan

Cell bertanggal layak mendapat satu peringatan khusus: keduanya dibandingkan sebagai konversi teksnya, sehingga workbook yang disimpan pada sistem tanggal 1904 dan yang pada sistem 1900 dapat dibandingkan sama atau berbeda dengan cara yang mengejutkan Anda jika nomor serial yang mendasarinya berbeda. Aturan sistem tanggal dibahas dalam nomor serial tanggal dan sistem 1904. Ketika fidelitas pemformatan atau level objek menjadi bagian dari pertanyaan, gabungkan diff dengan pass audit yang menghitung fitur tersebut pada masing-masing sisi

Perbandingan workbook, audit, dan konversi semuanya berjalan pada engine yang sama untuk Delphi dan C++Builder; daftar fitur lengkapnya ada di halaman komponen spreadsheet Delphi HotXLS