HotXLS vergelijkt twee werkmappen via TXLSXWorkbookCompare, dat werkbladen op naam koppelt, de gevulde cellen van elk paar doorloopt, en rapporteert wat verschilt als een gestructureerde lijst van verschilrecords en, op verzoek, als één leesbare regel per verschil. Er is geen Excel-installatie bij betrokken, en de vergelijking draait volledig op het geladen objectmodel in Delphi of C++Builder
De behoefte ontstaat meestal de eerste keer dat iemand vraagt wat er is veranderd. Een financiële werkmap komt terug van een beoordeling, een nachtelijke export wordt na een codewijziging opnieuw gegenereerd, of twee afdelingen sturen versies van hetzelfde sjabloon. Beide naast elkaar openen werkt voor één werkblad en faalt bij twintig. Bestanden byte voor byte vergelijken beantwoordt helemaal niets, omdat twee opslagacties van dezelfde werkmap verschillen op manieren die niemand iets kunnen schelen
Wat telt als een verschil?
De vergelijking rapporteert acht soorten, en de set is bewust klein: een werkblad toegevoegd of verwijderd, een gevulde cel toegevoegd of verwijderd, een cel waarvan de waarde is veranderd, een cel waarvan de formule is veranderd, en een samengevoegd bereik toegevoegd of verwijderd. Alles wordt uitgedrukt ten opzichte van de linkerwerkmap als basislijn, dus een toegevoegd item bestaat alleen rechts en een verwijderd item alleen links
Werkbladen worden op naam gekoppeld, niet op positie. Het herordenen van werkbladen levert daarom helemaal geen verschillen op, wat bijna altijd het gewenste gedrag is: een gebruiker die een tabblad versleept, is geen datawijziging. Een werkblad dat slechts aan één kant aanwezig is, rapporteert één item op werkbladniveau in plaats van elke gevulde cel erbinnen uit te breiden, wat een rapport van twee structureel verschillende werkmappen leesbaar houdt in plaats van duizenden regels lang
Waarde of formule, en hoe elk wordt vergeleken
Elke cel draagt een handtekening bij, en de regel is eenvoudig: een cel met een formule wordt vergeleken op zijn formuletekst met een voorafgaand isgelijkteken, en een cel zonder formule wordt vergeleken op zijn waarde omgezet naar tekst. Dat onderscheid doet er meer toe dan het op het eerste gezicht lijkt. Twee cellen kunnen hetzelfde weergegeven getal bevatten terwijl de ene een letterlijke waarde is en de andere een formule, en ze als gelijk behandelen zou precies de bewerking verbergen die het meest de moeite waard is om op te vangen in een beoordeelde werkmap
Het betekent ook dat een formule waarvan de tekst ongewijzigd is, geen verschil rapporteert, zelfs als het gecachte resultaat verschilt, wat het juiste gedrag is voor het vergelijken van opgestelde inhoud, en het verkeerde gedrag als u probeert herberekeningsdrift te detecteren. Voor die tweede vraag herberekent u beide werkmappen vóór het vergelijken, zodat de waarden die u vergelijkt de waarden zijn die de formules vandaag daadwerkelijk produceren
Een vergelijking uitvoeren
Compare neemt de twee geladen werkmappen en retourneert het aantal gevonden verschillen. De verschillenlijst is vervolgens beschikbaar op index, of kan naar elke TStrings worden weggeschreven:
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); // één leesbare regel per verschil
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;
Een regel geproduceerd door Report luidt bijvoorbeeld value changed: Data!A2: 10 -> 99, wat genoeg is voor een reviewer en genoeg voor een commitbericht. Dat is het mensgerichte oppervlak. Het programmatische oppervlak is het verschilrecord zelf, en dat is het oppervlak om te gebruiken wanneer de vergelijking een beslissing voedt in plaats van een document
Logica aansturen vanuit de gestructureerde verschillen
Elk verschil geeft zijn soort weer, de werkbladnaam, bij-één-beginnende rij en kolom voor items op celniveau, een A1-verwijzing voor items op samenvoegingsniveau, en de linker- en rechtertekst. Items op werkblad- en samenvoegingsniveau rapporteren rij en kolom als nul, en zo onderscheidt u ze zonder de soort te inspecteren:
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;
// Een beoordelingsbeleid dat alleen blokkeert op formulewijzigingen
if FormulaEdits > 0 then
raise Exception.CreateFmt(
'%d formula change(s) need sign-off', [FormulaEdits]);
end;
Twee eigenschappen van de uitvoer zijn het waard om te kennen voordat u er assertions tegen schrijft. De volgorde van items op celniveau volgt de interne doorloopvolgorde van de celopslag, dus tests moeten volgorde-onafhankelijk worden geschreven. En de formulehandtekening draagt zijn eigen voorafgaande isgelijkteken, wat betekent dat een via concatenatie opgebouwde beschrijvingsstring een verdubbelde == kan tonen; controleer de veldwaarden in plaats van de beschrijvende regel te parsen wanneer het resultaat logica aanstuurt
Waar workbook-diffing zich terugbetaalt
Drie toepassingen rechtvaardigen de functie op zichzelf. Regressietests van een rapportgenerator: bewaar een bekend-goede werkmap, genereer opnieuw, vergelijk, en laat de build falen bij elk onverwacht verschil. Wijzigingsbeoordeling: geef een reviewer het leesbare rapport in plaats van twee bestanden. En migratieverificatie: vergelijk na het converteren van een batch legacy-werkmappen elk resultaat met de bron om te bewijzen dat er niets verloren is gegaan
Dat derde geval sluit natuurlijk aan bij de inventarisatie- en auditpassages beschreven in het audit- en conversiewerkbank voor werkmappen, waar het tellen van wat een werkmap bevat vóór de conversie gebeurt en vergelijken erna. Als uw verschillen zich groeperen rond ingevoegde rijen, verklaren de regels voor het herschrijven van verwijzingen in aanpassing van formuleverwijzingen bij invoegen en verwijderen waarom formules die er ongewijzigd uitzien, als gewijzigd worden gerapporteerd
De grenzen, ronduit gesteld
De vergelijking omvat waarden, formules, samenvoegingen en de aanwezigheid van werkbladen. Ze vergelijkt geen getalnotaties, lettertypen, vullingen, regels voor voorwaardelijke opmaak, gegevensvalidaties, grafieken, afbeeldingen of gedefinieerde namen. Een cel waarvan de waarde identiek is maar waarvan de notatie is veranderd van Standaard naar Valuta, rapporteert geen verschil, wat correct is voor een datavergelijking en onvoldoende voor een opmaakbeoordeling
Cellen met datumwaarden verdienen één specifieke waarschuwing: ze worden vergeleken als hun tekstconversie, dus een werkmap opgeslagen volgens het 1904-datumsysteem en een volgens het 1900-systeem kan gelijk of ongelijk uitvallen op manieren die u verrassen als de onderliggende seriële getallen verschillen. De regels voor het datumsysteem worden behandeld in seriële datumgetallen en het 1904-systeem. Wanneer opmaak- of objectgetrouwheid deel uitmaakt van de vraag, combineer de diff dan met een auditpassage die deze functies aan elke kant telt
Werkmapvergelijking, auditing en conversie draaien allemaal op dezelfde engine voor Delphi en C++Builder; de volledige functielijst staat op de HotXLS Delphi-spreadsheetcomponentpagina