Tehnički članak

Strukturisane reference tabela u Delphi-ju sa HotXLS-om

HotXLS sada izračunava strukturisane reference tabela, tako da =SUM(Table1[Amount]) proizvodi broj umesto da bude preskočen. Resolver obrađuje Table[Column], Table[[Column]], raspone kolona kao što je Table[[Q1]:[Q4]], i specifikatore stavki [#Data], [#All], [#Headers] i [#Totals], razrešavajući svaku od njih u odnosu na model tabele radne sveske u trenutku parsiranja, dok se originalan tekst formule vraća bukvalno, bez izmena

Jedan oblik namerno nedostaje, i baš je onaj na koji ljudi prvi naiđu. Skraćenica za tekući red [@Column] nije podržana, iz strukturnog razloga koji vredi razumeti, a ne slepo zaobići

Zašto strukturisana referenca nije samo opseg sa prijateljskim imenom?

Zato što definisano ime zamrzava adresu, a referenca tabele ne. Napišite DataBlock kao ime koje pokazuje na Sheet1!$A$2:$D$100 i ono ostaje taj pravougaonik dok ga nešto ne prepiše. Napišite Sales[Amount] i to znači „kolona Amount tabele Sales”, kakav god da je opseg te tabele u trenutku kada se formula izračunava. Dodajte dvadeset redova tabeli i zbir ih obuhvata; nema reference koju treba prilagoditi, jer u formuli nikada nije ni postojala adresa

Upravo ta simbolička osobina je razlog zašto referenca ne može da se razreši zamenom niski. Resolver mora da pronađe tabelu po imenu u radnoj svesci, potraži kolonu po tekstu njenog zaglavlja, odluči koje redove pokriva traženi specifikator stavke, i proizvede konkretan pravougaonik. HotXLS ovo radi tokom kompajliranja formule kroz model tabele, zbog čega se formula napisana pre nego što je tabela porasla i dalje izračunava u odnosu na trenutni opseg tabele

Gramatika koju HotXLS razrešava

Podržana gramatika specifikacije pokriva jedan pravougaon rezultat i vredi je precizno izneti, jer Excel-ova dokumentacija predstavlja mnogo veću površinu nego što je većina mehanizama implementira. HotXLS prihvata [Col] i varijantu u zagradama [[Col]], gole specifikatore stavki [#Data], [#All], [#Headers] i [#Totals], kombinovan oblik [[#Data],[Col]], raspon unutar specifikatora stavke kao [[#Data],[Col1]:[Col2]], i prost raspon [Col1]:[Col2]

Ono što taj skup daje jeste svaki oblik reference koji proizvodi jedan susedan blok: kolonu, niz susednih kolona, isečak bilo koje od njih koji sadrži samo telo ili uključuje zaglavlje. Nesusedne unije i rezultati sa više oblasti su van tog skupa. Kada referenca ne može da se razreši, formula zadržava prethodno ponašanje preskakanja-bez-vrednosti umesto da zameni pogodak, tako da referenca koja se ne može razrešiti nikada ne postane verodostojan pogrešan broj

var
  Book: TXLSXWorkbook;
  Sheet: TXLSXWorksheet;
  Cols: TStringList;
begin
  Book := TXLSXWorkbook.Create;
  Cols := TStringList.Create;
  try
    Sheet := Book.Sheets.Add('Sales');
    Cols.Add('Region');
    Cols.Add('Q1');
    Cols.Add('Q2');
    Cols.Add('Amount');
    Sheet.Tables.Add('SalesTable', 'A1:D25', Cols);
    // ... upišite red zaglavlja i 24 reda podataka ...

    Sheet.Cells[27, 4].Formula := 'SUM(SalesTable[Amount])';
    Sheet.Cells[28, 4].Formula := 'SUM(SalesTable[[Q1]:[Q2]])';
    Sheet.Cells[29, 4].Formula := 'COUNTA(SalesTable[[#Data],[Region]])';
    Sheet.Cells[30, 4].Formula := 'ROWS(SalesTable[#All])';

    Book.Recalculate;
    Book.SaveAs('sales.xlsx');
  finally
    Cols.Free;
    Book.Free;
  end;
end;

Zašto je oblik tekućeg reda namerno isključen?

[@Column] i [#This Row] znače „ćelija te kolone u redu u kome se nalazi ova formula”. Vrednost stoga zavisi od pozicije ćelije koja se izračunava, ne samo od tabele. To je drugačija vrsta reference: ne pravougaonik koji kompajler može jednom da razreši, već razrešavanje po ćeliji koje mora da se ponovi za svaki red koji formula zauzima

HotXLS za te oblike vraća False iz resolver-a opsega tabele, što ih usmerava u putanju preskakanja-bez-vrednosti. Tekst formule se čuva i upisuje nazad nepromenjen, tako da se radna sveska koja koristi [@Amount] ispravno otvara u Excel-u posle prolaska kroz vašu aplikaciju; nedostaje samo vrednost koju bi izračunao HotXLS. Kada birate između odsutne vrednosti i vrednosti izračunate za pogrešan red, odsustvo je ono što možete da otkrijete

Praktično zaobilaženje je mehaničko: u radnoj svesci koju generišete, napišite ekvivalentnu relativnu referencu u A1 stilu, što Excel ionako interno čuva za veliki deo logike vezane za tabele. U radnoj svesci koju samo obrađujete, ostavite formulu na miru i pročitajte keširanu vrednost koju je Excel već sačuvao, što je obično ono što pipeline za učitavanje i izveštavanje želi

var
  Book: TXLSXWorkbook;
  Sheet: TXLSXWorksheet;
  Table: TXLSXTable;
  Row: Integer;
begin
  Book := TXLSXWorkbook.Create;
  try
    if Book.Open('sales.xlsx') <> 1 then Exit;
    Sheet := Book.Sheets[1];

    Table := Sheet.Tables.FindByName('SalesTable');
    if Table <> nil then
    begin
      // Pretraga u stilu recordset-a kroz telo tabele, rezultat reda indeksiran od 1
      Row := Table.FindFirst(Sheet, 'Region', 'EMEA');
      while Row > 0 do
      begin
        Log(VarToStr(Sheet.Cells[Row, 4].Value));
        Row := Table.FindNext(Sheet, 'Region', 'EMEA', Row);
      end;
    end;
  finally
    Book.Free;
  end;
end;

Šta se dešava kada tabela promeni oblik

Strukturisane reference se poništavaju umesto da se tiho preusmere kada ono što imenuju nestane. Obrišite kolonu i formule koje se pozivaju na tu kolonu se poništavaju onako kako ih poništava i Excel; obrišite ili preimenujte tabelu i reference na nju se tretiraju na isti način. Ovo je ispravno ponašanje i odražava obično prilagođavanje referenci, opisano u prilagođavanju referenci formula pri umetanju i brisanju, gde je posao mehanizma da formule ostanu poštene, a ne da izgledaju validno

Rast broja redova je suprotan slučaj i uopšte ne zahteva prilagođavanje. Pošto referenca imenuje tabelu, a ne pravougaonik, dodavanje redova unutar opsega tabele proširuje ono što [#Data] pokriva bez diranja ijedne formule. To je osobina zbog koje se tabele isplati koristiti u šablonu izveštaja: red sa ukupnim vrednostima nastavlja da sabira sve što je uvoz proizveo, koliko god redova to na kraju bilo

Disciplina vraćanja u izvoran oblik

HotXLS čuva originalan tekst formule. Radna sveska učitana sa SUM(SalesTable[Amount]) se snima sa SUM(SalesTable[Amount]), a ne sa razrešenom SUM(D2:D25). Ovo je važnije nego što deluje: korisnik koji otvori vaš izlaz u Excel-u očekuje da vidi formulu koju je napisao, a razrešena adresa bi tiho pretvorila samoodržavajući model u krhak model koji prestaje da pokriva nove redove

Dve povezane mogućnosti upotpunjuju sliku. Same definicije tabela, uključujući tabele bez zaglavlja i komentare po tabeli, vraćaju se u izvoran oblik kroz model tabele opisan u validaciji podataka, AutoFilter-u i Excel tabelama. A kada mnogo ćelija deli jedan obrazac, XLSX ih čuva jednom kao deljenu formulu, koja se širi i ponovo emituje, kako je pokriveno u širenju si za deljenu formulu. Strukturisane reference unutar deljenih formula prolaze kroz obe putanje, pa obe moraju ispravno da se ponašaju, i ponašaju se

HotXLS čita i piše XLS, XLSX i ODS iz Delphi-ja i C++Builder-a bez instaliranog Excel-a i bez automatizacije Office-a, izračunavajući formule u sopstvenom mehanizmu. Model tabele, mehanizam za formule i API za ponovno izračunavanje dokumentovani su na stranici HotXLS Delphi komponente za tabele