Technical Article

Extracción de información de resumen de documentos de archivos de Excel en Delphi

Al procesar grandes lotes de hojas de cálculo de Excel en una canalización automatizada, rara vez querrá cargar el documento completo en la memoria solo para saber de qué se trata. A menudo, los metadatos integrados dentro del archivo (autor, título, fecha de creación y propiedades personalizadas) son suficientes para enrutar, indexar o rechazar el documento. En el mundo de Microsoft Office, estos metadatos se conocen como Document Summary Information (Información de resumen del documento).

La extracción nativa de esta información en Delphi sin depender de la automatización OLE (que requiere que Excel esté instalado en la máquina anfitriona) requiere analizar directamente la estructura de archivos subyacente. En este artículo, analizaremos cómo funcionan los resúmenes de documentos en los archivos de Excel y cómo extraerlos de manera eficiente mediante el análisis de flujo (stream parsing) sin procesar.

Comprensión de los flujos de metadatos de Excel

Históricamente, los archivos de Excel más antiguos (.xls) se almacenan en formatos de documento compuesto OLE, actuando efectivamente como mini sistemas de archivos que contienen flujos y almacenamientos. Los metadatos se alojan en dos flujos específicos:

  • SummaryInformation: Contiene propiedades estándar como Título, Asunto, Autor, Palabras clave y Número de revisión.
  • DocumentSummaryInformation: Contiene propiedades extendidas como Empresa, Gerente y propiedades personalizadas definidas por el usuario.

Los archivos modernos de Excel (.xlsx) utilizan el formato Office Open XML (OOXML), que es una estructura XML comprimida (zipped). Aquí los metadatos se encuentran en docProps/core.xml, docProps/app.xml y docProps/custom.xml. Un componente robusto de análisis en Delphi debe manejar sin problemas ambas estructuras internas y, al mismo tiempo, exponer una API unificada al desarrollador.

Análisis de documentos compuestos OLE en Delphi

Para leer SummaryInformation de un archivo `.xls` heredado sin herramientas de terceros, debe analizar el almacenamiento estructurado OLE. Microsoft expone esto a través de la interfaz COM IPropertySetStorage. A continuación se muestra una implementación en bruto en Delphi que evita iniciar Excel:

uses
  System.SysUtils, System.Win.ComObj, Winapi.ActiveX, Winapi.Windows;

procedure ExtractXlsSummaryInfo(const FileName: string);
var
  Stg: IStorage;
  PropSetStg: IPropertySetStorage;
  PropStg: IPropertyStorage;
  PropSpec: TPropSpec;
  PropVariant: TPropVariant;
  Hr: HRESULT;
begin
  // Open the OLE Compound Document
  Hr := StgOpenStorage(PWideChar(WideString(FileName)), nil,
    STGM_READ or STGM_SHARE_DENY_WRITE, nil, 0, Stg);
    
  if Failed(Hr) then
    raise Exception.Create('Failed to open OLE storage. File may not be a valid .xls document.');

  // Query for the property set storage interface
  if Stg.QueryInterface(IPropertySetStorage, PropSetStg) = S_OK then
  begin
    // Open the SummaryInformation stream (FMTID_SummaryInformation)
    Hr := PropSetStg.Open(FMTID_SummaryInformation, STGM_READ or STGM_SHARE_EXCLUSIVE, PropStg);
    if Succeeded(Hr) then
    begin
      // Read the Author property (PIDSI_AUTHOR = 4)
      PropSpec.ulKind := PRSPEC_PROPID;
      PropSpec.propid := PIDSI_AUTHOR;
      
      if PropStg.ReadMultiple(1, @PropSpec, @PropVariant) = S_OK then
      begin
        if PropVariant.vt = VT_LPSTR then
          Writeln('Author: ', string(AnsiString(PropVariant.pszVal)));
        PropVariantClear(PropVariant);
      end;
    end;
  end;
end;

Extracción programática con HotXLS

Aunque la API COM de Windows funciona para archivos `.xls`, no funciona para los archivos modernos `.xlsx` (que son archivos ZIP). Además, usar la API COM multiplataforma (por ejemplo, en Linux o macOS a través de FireMonkey) es imposible. Las actualizaciones recientes del componente HotXLS introdujeron unidades dedicadas (por ejemplo, lxXlsSummary) para aislar y optimizar la lectura de estos flujos de resumen en ambos formatos de forma completamente nativa en código Delphi.

Un ejemplo multiplataforma

Mediante el uso de las interfaces XlsReadDocumentSummaryInformation y XlsReadSummaryInformation, puede capturar rápidamente las cadenas de metadatos tanto de `.xls` como de `.xlsx` sin preocuparse por la arquitectura del sistema de archivos subyacente.

uses
  lxXlsSummary;

var
  Summary: TXlsSummaryInfo;
  ExtendedInfo: TXlsDocumentSummaryInfo;
begin
  // Extract standard summary from an OOXML format seamlessly
  Summary := XlsReadSummaryInformation('C:\Data\FinancialReport.xlsx');
  try
    Writeln('Title: ', Summary.Title);
    Writeln('Author: ', Summary.Author);
    Writeln('Creation Date: ', DateTimeToStr(Summary.CreateTime));
  finally
    Summary.Free;
  end;

  // Extract extended document summary
  ExtendedInfo := XlsReadDocumentSummaryInformation('C:\Data\FinancialReport.xlsx');
  try
    Writeln('Company: ', ExtendedInfo.Company);
    Writeln('Manager: ', ExtendedInfo.Manager);
  finally
    ExtendedInfo.Free;
  end;
end;

Por qué es importante la extracción de resúmenes dedicada

El beneficio principal de este enfoque es el rendimiento y la seguridad de la memoria. Al evitar la creación de instancias de todo el modelo de objetos de documento (DOM) del libro de trabajo y analizar solo docProps/core.xml o los flujos de propiedades OLE, el tamaño de su aplicación se mantiene increíblemente pequeño. Si está indexando 10 000 archivos de Excel en un recurso compartido de red, intentar analizar completamente cada uno agotará su memoria y llevará horas. La extracción de resúmenes dedicada completa la misma tarea en segundos.

Además, la lectura nativa de los flujos garantiza que su aplicación pueda ejecutarse como un servicio en segundo plano o en un servidor Linux sin entorno gráfico (headless) sin invocar nunca a Excel.exe, un requisito fundamental para las arquitecturas modernas escalables.

Nota: Las herramientas integrales de análisis y extracción de metadatos de Excel están disponibles en el HotXLS VCL Component.