Tehnični članak

Primerjava dveh delovnih zvezkov Excel v Delphiju s HotXLS

HotXLS primerja dva delovna zvezka prek TXLSXWorkbookCompare, ki delovne liste poveže po imenu, prehodi zapolnjene celice vsakega para in javi, kaj se razlikuje, kot strukturiran seznam zapisov razlik in, na zahtevo, kot eno berljivo vrstico na razliko. Nobena namestitev Excela ni vpletena, primerjava pa v celoti teče na naloženem objektnem modelu v Delphiju ali C++Builderju

Potreba se običajno pojavi prvič, ko nekdo vpraša, kaj se je spremenilo. Finančni delovni zvezek se vrne s pregleda, nočni izvoz se po spremembi kode znova ustvari, ali pa dva oddelka pošljeta različici iste predloge. Odpiranje obeh druge ob drugi deluje za en list in odpove pri dvajsetih. Primerjava datotek bajt za bajtom ne odgovori na nič, saj se dve shranitvi istega delovnega zvezka razlikujeta na načine, za katere nikogar ni briga

Kaj šteje za razliko?

Primerjava javlja osem vrst, nabor pa je namerno majhen: dodan ali odstranjen list, dodana ali odstranjena zapolnjena celica, celica, katere vrednost se je spremenila, celica, katere formula se je spremenila, in dodano ali odstranjeno združeno območje. Vse je izraženo glede na levi delovni zvezek kot izhodišče, tako da dodan element obstaja samo na desni, odstranjen pa samo na levi

Listi so povezani po imenu in ne po položaju. Prerazporeditev delovnih listov zato sploh ne ustvari razlik, kar je skoraj vedno vedenje, ki ga želite: uporabnik, ki povleče zavihek, ni sprememba podatkov. List, prisoten samo na eni strani, javi en vnos na ravni lista namesto razširitve vsake zapolnjene celice znotraj njega, kar poročilo o dveh strukturno različnih delovnih zvezkih ohrani berljivo, namesto da bi bilo dolgo na tisoče vrstic

Vrednost ali formula, in kako se vsaka primerja

Vsaka celica prispeva podpis, pravilo pa je preprosto: celica, ki nosi formulo, se primerja po besedilu svoje formule z vodilnim enačajem, celica brez nje pa po svoji vrednosti, pretvorjeni v besedilo. To razlikovanje je pomembnejše, kot je videti na prvi pogled. Dve celici lahko nosita isto prikazano število, medtem ko je ena literal, druga pa formula, obravnava kot enaki pa bi prav skrila urejanje, ki ga je najbolj vredno ujeti v pregledanem delovnem zvezku

To tudi pomeni, da formula, katere besedilo je nespremenjeno, ne javi razlike, tudi če se njen predpomnjeni rezultat razlikuje, kar je pravilno vedenje za primerjavo avtorske vsebine in napačno vedenje, če poskušate zaznati zamik zaradi ponovnega izračuna. Za to drugo vprašanje oba delovna zvezka pred primerjavo ponovno izračunajte, tako da so vrednosti, ki jih primerjate, tiste, ki jih formule dejansko dajo danes

Izvajanje primerjave

Compare sprejme dva naložena delovna zvezka in vrne število najdenih razlik. Seznam razlik je nato na voljo po indeksu ali pa ga lahko izpišete v poljuben 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);              // ena berljiva vrstica na razliko
      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;

Vrstica, ki jo ustvari Report, se glasi na primer value changed: Data!A2: 10 -> 99, kar zadošča za pregledovalca in zadošča za sporočilo o uveljavitvi. To je površina, namenjena ljudem. Programska površina je sam zapis razlike, in prav to uporabite, kadar primerjava napaja odločitev in ne dokumenta

Vodenje logike iz strukturiranih razlik

Vsaka razlika izpostavi svojo vrsto, ime lista, od ena štete vrstico in stolpec za vnose na ravni celice, sklic A1 za vnose na ravni združitve ter levo in desno besedilo. Vnosi na ravni lista in ravni združitve javijo vrstico in stolpec kot nič, po čemer jih ločite, ne da bi pregledovali vrsto:

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;

  // Pravilnik pregleda, ki blokira samo pri urejanju formul
  if FormulaEdits > 0 then
    raise Exception.CreateFmt(
      '%d formula change(s) need sign-off', [FormulaEdits]);
end;

Preden zoper izhod pišete trditve, je vredno poznati dve njegovi lastnosti. Vrstni red vnosov na ravni celice sledi internemu vrstnemu redu prehoda po shrambi celic, zato je treba teste pisati neodvisno od vrstnega reda. Podpis formule pa nosi svoj lasten vodilni enačaj, kar pomeni, da lahko opisni niz, zgrajen s spajanjem, pokaže podvojen ==; kadar rezultat vodi logiko, preverjajte vrednosti polj namesto razčlenjevanja opisne vrstice

Kje se primerjava delovnih zvezkov izplača

Tri rabe že same po sebi upravičijo to funkcijo. Regresijsko testiranje generatorja poročil: obdržite znano dober delovni zvezek, znova ustvarite, primerjajte in ob vsaki nepričakovani razliki neuspešno zaključite izgradnjo. Pregled sprememb: pregledovalcu izročite berljivo poročilo namesto dveh datotek. In preverjanje migracije: po pretvorbi paketa podedovanih delovnih zvezkov vsak rezultat primerjajte z izvirnikom, da dokažete, da se ni nič izgubilo

Ta tretji primer se naravno poveže s prehodi popisa in revizije, opisanimi v delovnem prostoru za revizijo in pretvorbo delovnih zvezkov, kjer se štetje vsebine delovnega zvezka zgodi pred pretvorbo, primerjava pa po njej. Če se vaše razlike gručijo okoli vstavljenih vrstic, pravila prepisovanja sklicev v prilagoditvi sklicev formul ob vstavljanju in brisanju pojasnijo, zakaj se formule, ki so videti nespremenjene, javijo kot spremenjene

Omejitve, povedane naravnost

Primerjava zajema vrednosti, formule, združitve in prisotnost listov. Ne primerja številskih oblik, pisav, polnil, pravil pogojnega oblikovanja, preverjanja podatkov, grafikonov, slik ali definiranih imen. Celica z enako vrednostjo, katere oblika pa se je spremenila iz Splošno v Valuta, ne javi razlike, kar je pravilno za primerjavo podatkov in nezadostno za pregled oblikovanja

Celice z datumskimi vrednostmi si zaslužijo eno posebno opozorilo: primerjajo se prek svoje besedilne pretvorbe, tako da se lahko delovni zvezek, shranjen v datumskem sistemu 1904, in tak v sistemu 1900 primerjata kot enaka ali neenaka na način, ki vas preseneti, če se osnovna zaporedna števila razlikujejo. Pravila datumskega sistema so opisana v zaporednih številkah datumov in sistemu 1904. Kadar je del vprašanja zvestoba oblikovanja ali objektov, primerjavo razlik združite s prehodom revizije, ki na vsaki strani prešteje te funkcije

Primerjava, revizija in pretvorba delovnih zvezkov vse tečejo na istem mehanizmu za Delphi in C++Builder; celoten seznam funkcij je na strani komponente HotXLS Excel za Delphi