Documentación de HotXLS

API de tabla dinámica XLS clásica

HotXLS admite inspección con tipos, autoría y materialización de resultados de tablas dinámicas para libros de trabajo XLS y XLSX. La carga de XLSX basada en relaciones resuelve nombres de partes del paquete arbitrarios y restaura registros de caché, elementos compartidos, metadatos de campos, filtros, agrupaciones, definiciones calculadas, formatos y extensiones en el modelo público. La entrada XLS Classic mantiene sus registros de tabla dinámica originales disponibles para round-trips de guardado fieles

Modelo tipado y de ida y vuelta

Cuando un libro de trabajo clásico ya contiene tablas dinámicas, el lector preserva los registros BIFF en bruto y además expone un modelo tipado. Las tablas y cachés cargadas desde un archivo clásico conservan FromRawBlobs = True, de modo que la salida al guardar reproduce los bytes originales por fidelidad. Las tablas dinámicas XLSX se cargan y guardan a través de las relaciones del paquete que las contiene, mientras que las tablas dinámicas creadas por código usan el escritor tipado

const
  xlPivotBaseItemPrevious = $7FFB;
  xlPivotBaseItemNext = $7FFC;

type
  TXLSPivotFieldAxis = (xlpfaNone, xlpfaRowField, xlpfaColumnField, xlpfaPageField, xlpfaDataField);
  TXLSPivotAggregation = (xlpaSum, xlpaCount, xlpaAverage, xlpaMax, xlpaMin, xlpaProduct, xlpaCountNums, xlpaStdDev, xlpaStdDevP, xlpaVar, xlpaVarP);
  TXLSPivotShowDataAs = (xlpsdaNormal, xlpsdaDifference, xlpsdaPercent, xlpsdaPercentDiff, xlpsdaRunTotal, xlpsdaPercentOfRow, xlpsdaPercentOfCol, xlpsdaPercentOfTotal, xlpsdaIndex);
  TXLSPivotExtendedShowDataAs = (xlpesdaNone, xlpesdaPercentOfParent, xlpesdaPercentOfParentRow, xlpesdaPercentOfParentColumn, xlpesdaPercentOfRunningTotal, xlpesdaRankAscending, xlpesdaRankDescending);
  TXLSPivotSubtotal = (xlpsDefault, xlpsSum, xlpsCount, xlpsAverage, xlpsMax, xlpsMin, xlpsProduct, xlpsCountNums, xlpsStdDev, xlpsStdDevP, xlpsVar, xlpsVarP);
  TXLSPivotSubtotals = set of TXLSPivotSubtotal;
  TXLSPivotDesignerZone = (xlpdzAvailable, xlpdzRows, xlpdzColumns, xlpdzFilters, xlpdzValues);

  TXLSPivotCacheValue = record
    ValueType: TXLSPivotCacheFieldType;
  end;

  TXLSPivotCacheField = class
    property Name: WideString;
    property FieldType: TXLSPivotCacheFieldType;
    property ItemCount: Integer;
    property Items[Index: Integer]: TXLSPivotCacheItem;
  end;

  TXLSPivotCache = class
    property CacheId: Integer;
    property SourceRangeSheet: WideString;
    property SourceFirstRow: Integer;
    property SourceFirstCol: Integer;
    property SourceLastRow: Integer;
    property SourceLastCol: Integer;
    property RecordCount: Integer;
    property FieldCount: Integer;
    property Fields[Index: Integer]: TXLSPivotCacheField;
    property RecordIndices[RecordIdx, FieldIdx: Integer]: Integer;
    property FromRawBlobs: Boolean;
  end;

  TXLSPivotCaches = class
    function Add: TXLSPivotCache;
    function FindByCacheId(ACacheId: Integer): TXLSPivotCache;
    property Count: Integer;
    property Items[Index: Integer]: TXLSPivotCache;
  end;

  TXLSPivotField = class
    function AddItem: TXLSPivotItem;
    function AddCalculatedItem(const AName, AFormula: WideString): TXLSPivotCalculatedItem;
    property Name: WideString;
    property Axis: TXLSPivotFieldAxis;
    property CacheFieldIndex: Integer;
    property ItemCount: Integer;
    property Items[Index: Integer]: TXLSPivotItem;
    property SubtotalMask: Word;
    property Subtotals: TXLSPivotSubtotals;
    property PageItemIndex: Integer;
    property SortType: TXLSPivotFieldSortType;
    property SortDataField: Integer;
    property Filters: TXLSPivotFilters;
  end;

  TXLSPivotDataField = class
    property Field: TXLSPivotField;
    property Aggregation: TXLSPivotAggregation;
    property NumberFormat: Word;
    property DisplayName: WideString;
    property ShowDataAs: TXLSPivotShowDataAs;
    property ExtendedShowDataAs: TXLSPivotExtendedShowDataAs;
    property BaseField: Integer;
    property BaseItem: Integer;
  end;

  TXLSPivotSupplementalRecord = class
    property RecID: Word;
    property BodyLength: Integer;
    property Body[Index: Integer]: Byte;
  end;

  TXLSPivotTable = class
    function AddField(const AName: WideString; ACacheFieldIndex: Integer): TXLSPivotField;
    function FindFieldByName(const AName: WideString): TXLSPivotField;
    function SetFieldAxis(const AName: WideString; AAxis: TXLSPivotFieldAxis): TXLSPivotField;
    function AddRowField(const AName: WideString): TXLSPivotField;
    function AddColumnField(const AName: WideString): TXLSPivotField;
    function AddPageField(const AName: WideString): TXLSPivotField;
    function AddDataField(AField: TXLSPivotField; AAggregation: TXLSPivotAggregation): TXLSPivotDataField;
    function AddDataFieldByName(const AName: WideString; AAggregation: TXLSPivotAggregation = xlpaSum): TXLSPivotDataField;
    function AddCalculatedMember(const AName, AFormula: WideString): TXLSPivotCalculatedMember;
    function AddSupplementalRecord(ARecID: Word; const ABody: TBytes): TXLSPivotSupplementalRecord;
    function Make(AWriter: TlxPivotResultWriter): Integer;
    property Name: WideString;
    property DataCaption: WideString;
    property CacheId: Integer;
    property Cache: TXLSPivotCache;
    property FieldCount: Integer;
    property Fields[Index: Integer]: TXLSPivotField;
    property DataFieldCount: Integer;
    property DataFields[Index: Integer]: TXLSPivotDataField;
    property RowGrandTotals: Boolean;
    property ColumnGrandTotals: Boolean;
    property MaterializeGrandTotalRow: Boolean;
    property MaterializeGrandTotalColumn: Boolean;
    property SupplementalRecordCount: Integer;
    property SupplementalRecords[Index: Integer]: TXLSPivotSupplementalRecord;
    property FromRawBlobs: Boolean;
  end;

  TXLSPivotDesigner = class
    constructor Create(APivotTable: TXLSPivotTable = nil);
    procedure ClearLayout;
    function MoveField(const AName: WideString; AZone: TXLSPivotDesignerZone; APosition: Integer = -1): Boolean;
    function SetAggregation(const AName: WideString; AAggregation: TXLSPivotAggregation): Boolean;
    function Validate(out ErrorText: WideString): Boolean;
    function Apply(AWriter: TlxPivotResultWriter): Integer;
    property PivotTable: TXLSPivotTable;
    property FieldCount: Integer;
    property Fields[Index: Integer]: TXLSPivotDesignerField;
  end;

  TXLSPivotTables = class
    function Add: TXLSPivotTable;
    function FindByName(const AName: WideString): TXLSPivotTable;
    property Count: Integer;
    property Items[Index: Integer]: TXLSPivotTable;
  end;
      

Puntos de entrada de hoja de cálculo y libro de trabajo

type
  TXLSWorksheet = class
    function AddPivotTable(const SourceRangeA1: WideString; DestRow, DestCol: Integer; const Name: WideString): TXLSPivotTable;
    function PivotSetDataFieldFormat(DataField: TXLSPivotDataField; const FormatStr: WideString): Word;
    property PivotTables: TXLSPivotTables;
  end;

  TXLSWorkbook = class
    property PivotCaches: TXLSPivotCaches;
    function RegisterNumFormat(const FormatStr: WideString): Word;
end;
      

RegisterNumFormat registra una cadena de formato numérico y devuelve su índice ifmt de BIFF8, que es lo que esperan TXLSPivotDataField.NumberFormat y TXLSPivotCacheField.NumberFormat; registrar dos veces la misma cadena devuelve el mismo índice

DestRow y DestCol están basados en uno, al igual que Cells[Row, Col], así que AddPivotTable('Data!A1:C9', 3, 1, 'SalesPivot') ancla la tabla dinámica en A3. Las posiciones sobre TXLSPivotTable (FirstRow .. FirstDataCol) y el rango de origen sobre TXLSPivotCache también están basados en uno, igual que en el motor XLSX; un ancla fuera de la hoja de 65,536 x 256 devuelve nil

Crear un diseño de tabla dinámica de arrastrar y soltar

TXLSPivotDesigner es un modelo de diseño no visual que puede respaldar interfaces de listas de campos en VCL, FMX, web o línea de comandos, sin acoplar la lógica de la tabla dinámica a un solo toolkit de UI

Cada campo informa una zona disponible, de fila, de columna, de filtro o de valor, más su posición determinista; MoveField aplica una colocación, SetAggregation cambia un campo de valores, Validate informa los diseños incompletos, y Apply valida y materializa el resultado a través del escritor de tablas dinámicas normal

Los campos de valores numéricos y de fecha nuevos usan xlpaSum de forma predeterminada, mientras que los campos de texto, booleanos, de error, vacíos y mixtos usan xlpaCount

var
  Designer: TXLSPivotDesigner;
  ErrorText: WideString;
begin
  Designer := TXLSPivotDesigner.Create(Pivot);
  try
    Designer.MoveField('Region', xlpdzRows);
    Designer.MoveField('Quarter', xlpdzColumns);
    Designer.MoveField('Closed', xlpdzFilters);
    Designer.MoveField('Revenue', xlpdzValues);
    Designer.SetAggregation('Revenue', xlpaAverage);
    if Designer.Validate(ErrorText) then
      Designer.Apply(ResultWriter.WriteCell);
  finally
    Designer.Free;
  end;
end;
      

Crear una tabla dinámica

uses lxHandle;

var
  Workbook: TXLSWorkbook;
  SourceSheet, PivotSheet: TXLSWorksheet;
  Pivot: TXLSPivotTable;
  RowField: TXLSPivotField;
  DataField: TXLSPivotDataField;
begin
  Workbook := TXLSWorkbook.Create;
  try
    SourceSheet := Workbook.Sheets[1];
    SourceSheet.Name := 'SalesData';
    SourceSheet.Cells[1, 1].Value := 'Region';
    SourceSheet.Cells[1, 2].Value := 'Product';
    SourceSheet.Cells[1, 3].Value := 'Revenue';

    PivotSheet := Workbook.Sheets.Add;
    PivotSheet.Name := 'PivotReport';
    Pivot := PivotSheet.AddPivotTable('SalesData!A1:C20', 4, 1, 'SalesPivot');
    RowField := Pivot.AddRowField('Region');
    Pivot.AddColumnField('Product');
    DataField := Pivot.AddDataFieldByName('Revenue', xlpaSum);
    RowField.Subtotals := [xlpsSum];
    PivotSheet.PivotSetDataFieldFormat(DataField, '$#,##0.00');

    Workbook.SaveAs('pivot-report.xls');
  finally
    Workbook.Free;
  end;
end;
      

Mostrar valores como

Establezca ShowDataAs en cada campo de datos antes de llamar a Make o de guardar el libro de trabajo. Difference, Percent y PercentDiff requieren un índice de campo dinámico BaseField de base 0 más un BaseItem. RunTotal requiere solo BaseField. Los modos de fila, columna, total e índice obtienen sus denominadores de los registros de origen con la agregación configurada

Un BaseItem explícito es un índice de elemento de base 0 dentro del campo dinámico base. Use xlPivotBaseItemPrevious o xlPivotBaseItemNext para comparaciones con elementos adyacentes. Las intersecciones de comparación faltantes quedan en blanco, mientras que un denominador cero presente produce #DIV/0!

DataField := Pivot.AddDataFieldByName('Revenue', xlpaSum);
DataField.ShowDataAs := xlpsdaPercentDiff;
DataField.BaseField := 0;
DataField.BaseItem := xlPivotBaseItemPrevious;
CellsWritten := Pivot.Make(ResultWriter.WriteCell);
      

Filtrado, agrupación y ordenación

Make aplica los elementos ocultos y las selecciones de página antes de construir los dominios, y luego evalúa los filtros de título, fecha, conteo, porcentaje, suma y valor. Los rangos numéricos, los grupos de calendario y los grupos discretos usan los metadatos de agrupación de campos de caché antes de la agregación. SortType selecciona el orden estable de etiquetas, mientras que SortDataField selecciona el campo de valores de base 0 para un orden estable por valores de datos

Expresiones calculadas

Los campos de caché calculados se ejecutan una vez por registro de origen, los elementos calculados se ejecutan sobre los agregados de elementos hermanos, y los miembros calculados con MemberType = 'data' agregan campos de valores virtuales después de la agregación de origen. Los nombres de fórmulas no distinguen mayúsculas y pueden ir entre corchetes o comillas. Se admiten la aritmética, las comparaciones, los porcentajes, los paréntesis y las funciones numéricas y lógicas comunes, con pasadas repetidas de dependencias para definiciones calculadas acíclicas

ProfitField := Pivot.Cache.AddField('Profit', xlpcftNumber);
ProfitField.Formula := '=Revenue-Cost';
ProfitField.DatabaseField := False;
Pivot.AddDataField(Pivot.AddField('Profit', 4), xlpaSum);

RegionField.AddCalculatedItem('Combined', '=North+South');
Pivot.AddCalculatedMember('Margin', '=Profit/Revenue').MemberType := 'data';
      

Subtotales y totales generales

Cada campo de fila o columna puede materializar cualquier función de subtotal configurada encima o debajo de sus elementos de detalle mediante Subtotals y SubtotalTop. RowGrandTotals y ColumnGrandTotals controlan la política guardada del libro de trabajo, mientras que MaterializeGrandTotalRow y MaterializeGrandTotalColumn hacen que los callbacks de resultados incluyan la salida explícita de totales generales sin volver a escanear los registros de origen

Modos extendidos de mostrar valores

ExtendedShowDataAs proporciona porcentaje del padre, porcentaje de la fila padre, porcentaje de la columna padre, porcentaje del total acumulado y rango ascendente o descendente. Estos modos usan el modelo de extensión XLSX y no emiten valores de campos de datos BIFF clásicos no soportados

Inspeccionar un libro de trabajo dinámico existente

Workbook.Open('excel-authored-pivot.xls');
for SheetIndex := 1 to Workbook.Sheets.Count do
begin
  Sheet := Workbook.Sheets[SheetIndex];
  for PivotIndex := 0 to Sheet.PivotTables.Count - 1 do
  begin
    Pivot := Sheet.PivotTables[PivotIndex];
    Writeln(Pivot.Name);
    Writeln(Pivot.FieldCount);
    if Assigned(Pivot.Cache) then
      Writeln(Pivot.Cache.SourceRangeSheet);
  end;
end;
      

Temas relacionados