Tehnički članak

Usporedba dviju Excel radnih knjiga u Delphiju uz HotXLS

HotXLS uspoređuje dvije radne knjige putem TXLSXWorkbookCompare, koji uparuje radne listove prema nazivu, prolazi kroz popunjene ćelije svakog para i prijavljuje što se razlikuje kao strukturirani popis zapisa razlika te, na zahtjev, kao jedan čitljiv redak po razlici. Nije uključena nikakva instalacija Excela, a usporedba se u potpunosti izvodi nad učitanim objektnim modelom u Delphiju ili C++Builderu

Potreba se obično pojavi prvi put kada netko pita što se promijenilo. Financijska radna knjiga vraća se iz revizije, noćni izvoz ponovno se generira nakon izmjene koda, ili dva odjela pošalju verzije istog predloška. Otvaranje obje jedna pored druge funkcionira za jedan list, a zakazuje za dvadeset. Usporedba datoteka bajt po bajt ne odgovara na ništa, jer se dva spremanja iste radne knjige razlikuju na načine do kojih nikome nije stalo

Što se smatra razlikom?

Usporedba prijavljuje osam vrsta, a skup je namjerno malen: dodan ili uklonjen list, dodana ili uklonjena popunjena ćelija, ćelija čija se vrijednost promijenila, ćelija čija se formula promijenila i dodan ili uklonjen spojeni raspon. Sve se izražava naspram lijeve radne knjige kao osnove, pa dodana stavka postoji samo na desnoj strani, a uklonjena samo na lijevoj

Listovi se uparuju prema nazivu, a ne prema poziciji. Preraspoređivanje radnih listova stoga ne proizvodi nikakve razlike, što je gotovo uvijek ponašanje koje želite: korisnik koji povlači karticu nije promjena podataka. List prisutan samo na jednoj strani prijavljuje jedan unos na razini lista umjesto da proširi svaku popunjenu ćeliju unutar njega, čime izvještaj o dvije strukturno različite radne knjige ostaje čitljiv umjesto da ima tisuće redaka

Vrijednost ili formula, i kako se svaka uspoređuje

Svaka ćelija doprinosi potpis, a pravilo je jednostavno: ćelija koja nosi formulu uspoređuje se prema tekstu svoje formule s vodećim znakom jednakosti, a ćelija bez nje uspoređuje se prema svojoj vrijednosti pretvorenoj u tekst. Ta razlika važnija je nego što se čini na prvi pogled. Dvije ćelije mogu prikazivati isti broj dok je jedna doslovna vrijednost, a druga formula, a njihovo tretiranje kao jednakih sakrilo bi upravo onu izmjenu koju je najvažnije uočiti u revidiranoj radnoj knjizi

To također znači da formula čiji tekst nije promijenjen ne prijavljuje razliku čak i ako se njezin predmemorirani rezultat razlikuje, što je ispravno ponašanje za usporedbu autorskog sadržaja, a pogrešno ponašanje ako pokušavate otkriti odstupanje ponovnog izračuna. Za to drugo pitanje, ponovno izračunajte obje radne knjige prije usporedbe, tako da su vrijednosti koje uspoređujete one koje formule danas doista proizvode

Pokretanje usporedbe

Compare prima dvije učitane radne knjige i vraća broj pronađenih razlika. Popis razlika zatim je dostupan po indeksu, ili se može ispisati u bilo koji TStrings:

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);              // jedan čitljiv redak po razlici
      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;

Redak koji proizvede Report glasi otprilike value changed: Data!A2: 10 -> 99, što je dovoljno za recenzenta i dovoljno za poruku commita. To je površina okrenuta prema čovjeku. Programska površina je sam zapis razlike, i njega treba koristiti kada usporedba napaja odluku, a ne dokument

Vođenje logike iz strukturiranih razlika

Svaka razlika izlaže svoju vrstu, naziv lista, redak i stupac s bazom 1 za unose na razini ćelije, A1 referencu za unose na razini spajanja, te lijevi i desni tekst. Unosi na razini lista i na razini spajanja prijavljuju redak i stupac kao nulu, a upravo tako ih razlikujete bez provjere vrste:

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;

  // Politika revizije koja blokira samo kod izmjena formula
  if FormulaEdits > 0 then
    raise Exception.CreateFmt(
      '%d formula change(s) need sign-off', [FormulaEdits]);
end;

Dva svojstva izlaza vrijedi znati prije pisanja provjera (assertions) nad njim. Redoslijed unosa na razini ćelije prati unutarnji redoslijed obilaska spremišta ćelija, pa testove treba pisati neovisno o redoslijedu. A potpis formule nosi vlastiti vodeći znak jednakosti, što znači da niz opisa izgrađen konkatenacijom može prikazati udvostručeni ==; kada rezultat pokreće logiku, provjerite vrijednosti polja umjesto raščlambe opisnog retka

Gdje se isplati usporedba radnih knjiga

Tri primjene same po sebi opravdavaju ovu značajku. Regresijsko testiranje generatora izvještaja: zadržite poznato ispravnu radnu knjigu, ponovno generirajte, usporedite i zaustavite build na svakoj neočekivanoj razlici. Revizija izmjena: dajte recenzentu čitljiv izvještaj umjesto dvije datoteke. I provjera migracije: nakon pretvorbe paketa naslijeđenih radnih knjiga usporedite svaki rezultat s izvorom kako biste dokazali da ništa nije izgubljeno

Taj treći slučaj prirodno se nadopunjuje s prolazima popisa i revizije opisanima u radnoj klupi za reviziju i pretvorbu radnih knjiga, gdje se brojanje onoga što radna knjiga sadrži odvija prije pretvorbe, a usporedba nakon nje. Ako se vaše razlike gomilaju oko umetnutih redaka, pravila prepisivanja referenci u prilagodbi referenci formula pri umetanju i brisanju objašnjavaju zašto se formule koje izgledaju nepromijenjeno prijavljuju kao promijenjene

Ograničenja, jasno rečeno

Usporedba obuhvaća vrijednosti, formule, spajanja i prisutnost listova. Ne uspoređuje formate brojeva, fontove, ispune, pravila uvjetnog oblikovanja, provjere valjanosti podataka, grafikone, slike ili definirane nazive. Ćelija čija je vrijednost identična, ali čiji se format promijenio iz General u Currency, ne prijavljuje razliku, što je ispravno za usporedbu podataka, a nedovoljno za reviziju oblikovanja

Ćelije s vrijednostima datuma zaslužuju jedno specifično upozorenje: uspoređuju se kao svoja tekstualna pretvorba, pa radna knjiga pohranjena u sustavu datuma 1904 i ona u sustavu 1900 mogu se usporediti kao jednake ili nejednake na načine koji vas iznenade ako se temeljni serijski brojevi razlikuju. Pravila sustava datuma opisana su u serijskim brojevima datuma i sustavu 1904. Kada je vjernost oblikovanja ili razine objekata dio pitanja, kombinirajte usporedbu s prolazom revizije koji broji te značajke na svakoj strani

Usporedba, revizija i pretvorba radnih knjiga sve se izvode na istom mehanizmu za Delphi i C++Builder; cjelokupni popis značajki nalazi se na stranici HotXLS Delphi komponente proračunske tablice