Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Semplici report in Excel

Esportare i risultati di query, viste o SP, in un formato compatibile con Excel
Esportare i risultati di query, viste o SP, in un formato compatibile con Excel
Link copiato negli appunti

In questo articolo esaminiamo una semplicissima tecnica, già proposta in Classic ASP da Roberto Caccianini, per generare report importabili da Excel con ASP.NET.

La tecnica di base consiste nel costruire il markup di un foglio excel inserendovi i dati prelevati da una query o da una Stored Procedure. Ciò che cercheremo di fare è rendere tutto più semplice creando una piccola classe che compia questo lavoro al posto nostro e riusandola a piacere.

Per poter visualizzare il file generato, se non abbiamo installato il foglio elettronico di Microsoft, avremo bisogno almeno del visualizzatore Excel.

Il file "HTML"

Ormai è noto che si può salvare un file Excel come "pagina HTML", sfruttando questa caratteristica possiamo evitare alcuni problemi di permessi e autorizzazioni che potremo incontrare usando, ad esempio, gli Iterop di Office (PIA) all'interno di una applicazione Web, specie se in Hosting.

Diamo uno sguardo alla struttura che dovrà avere il nostro file. Di seguito il namespace e l'XML che bisogna inserire all'inizio di un qualsiasi file di excel, con estensione ".xls".

Listato 1. Esempio di header del file Excel

<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40">

<head>
  <meta http-equiv=Content-Type content="text/html; charset=windows-1252">
  <meta name=ProgId content=Excel.Sheet><meta name=Generator content="Microsoft Excel 9">
  <!--[if gte mso 9]>
  <xml>
  <!-- Descrizione di tutto il file -->
  <x:ExcelWorkbook>
    <!-- Fogli di lavoro -->
    <x:ExcelWorksheets>
      <!-- Definizione del foglio -->
      <x:ExcelWorksheet>
        <!-- Nome del foglio -->
        <x:Name>mioFoglio</x:Name>
        <!-- opzioni -->
        <x:WorksheetOptions>
          <x:Selected/>
          <x:ProtectContents>False</x:ProtectContents>
          <x:ProtectObjects>False</x:ProtectObjects>
          <x:ProtectScenarios>False</x:ProtectScenarios>
        </x:WorksheetOptions>
      </x:ExcelWorksheet>
    </x:ExcelWorksheets>
    <!-- Protezione a livello di file -->
    <x:ProtectStructure>False</x:ProtectStructure>
    <x:ProtectWindows>False</x:ProtectWindows>
  </x:ExcelWorkbook>
  </xml>
  <![endif]-->
</head>

A questo header possiamo associare dei particolari fogli di stile CSS, con regole e caratteristiche molto simili a quelle utilizzate per HTML/XHTML, utilizzando il tag <style>.

Il contenuto della tabella sarà inserito nella sezione <body> del file come una comunissima <table> in HTML.

La classe

Lo schema UML (By Visual Studio) evidenzia la struttura della classe che farà da motore per i nostri file.

Le proprietà

  • Connessione: a questa proprietà serve per definire la stringa di connessione al database. Nel nostro caso usiamo un DB di tipo SQL Server, ma avremmo tranquillamente potuto usare dei Driver ODBC o OLEDB.
  • DaFormattare: è un valore booleano che indica la presenza di stili per la formattazione della tabella.
  • DestPath: serve per indicare il full-path name, ovvero il percorso completo del file Excel da generare. In questo modo dalla pagina chiamante possiamo usare il metodo Server.MapPath() per posizionare correttamente il file nel file system del server Web.
  • Query: stringa contenente le istruzioni SQL (query o SP) per prelevare le informazioni dal database.
  • Stile: un eventuale foglio di stile accessorio.
  • HeaderPath: indicare il full-path name, di un file di testo in cui abbiamo salvato il tipico header di un file Excel.

Come immaginiamo, dovremo anzitutto impaginare i dati come faremmo per una classica tabella HTML. Quindi tramite l'ausilio di un file .css possiamo andare modificarne la formattazione.

I metodi

Vediamo come implementare la logica di lettura dei dati. Abbiamo bisogno di creare una DataTable e sfruttarne le funzionalità per poi poterle riflettere nel file di excel. Pensiamo ad esempio di voler controllare l'allineamento dei dati a seconda del tipo di dato (Numero, Stringa) oppure di voler modificare l'intestazione con i nomi delle colonne.

Spendiamo allora qualche metodo per semplificare la connessione al DataBase. Alcuni metodi sono stati implementati per lavorare con SQL Server, ma possiamo immaginare di virtualizzare la classe ed implementarla per i diversi connettori.

Abbiamo immaginato:

  • il metodo CostruisciConnessione() che semplicemente ritorna una SQLConnection dopo aver verificato la possibilità di stabilire il collegamento al DB,
  • il metodo CostruisciDati() che effettua la query e ritorna una DataTable già strutturata con l'impostazione del file ".xls",
  • CostruisciFile() è il metodo centrale che costruisce il markup del file e della tabella in particolare.

    Riconosce i DataType e i DataValue di ogni colonna e ne fornisce la opportuna visualizzazione.

I primi due metodi sono molto semplici, servono per creare un SQLCommand che legge la query da noi impostata, dichiarare un DataAdapter che riempie le tabelle di un DataSet. La tabella "numero 0" di questo DataSet (mioDataSet.Tables[0]) è quella che contiene il risultato della query e sarà esaminata dal metodo CostruisciFile() che usiamo per generare tutto il markup.

Tutto si gioca nel metodo CostruisciFile(). Ne abbiamo implementata una versione molto semplice che si limita a:

  • caricare un header esterno (in realtà lo stesso header potrebbe essere generato permettendo ad esempio la gestione di fogli multipli e altre proprietà)
  • applicare o meno un semplice foglio di stile (il foglio di stile è minimale, ma si può abbellire inserendo altre caratteristiche nella classe come ad esempio le righe alterne per i dati).
  • leggere i dati dalla DataTable e formattarli come una normale tabella XHTML.

Esaminiamo solo alcuni spezzoni di codice che possono essere di maggior rilevanza. Ad esempio la generazione automatica delle intestazioni per le colonne, e l'inserimento dei dati che tenga conto dei tipi di dato che vengono dal database.

Listato 2. Stralcio di CostruisciFile(): la costruzione della tabella

...

// inserisce i tag iniziali
fileDestinazione.Append("<body><table>");

// finalmente inserisce i dati
DataTable tabella = CostruisciDati();

// comincia dai nomi delle colonne
fileDestinazione.Append("<tr>");

Hashtable Colonne = new Hashtable();

// per ogni colonna scrive il nome nel file
foreach(DataColumn colonna in tabella.Columns)
{
  fileDestinazione.Append("<th>"+colonna.ColumnName+"</th>");

  // registra il nome ed il tipo in una hashtable
  Colonne.Add(colonna.ColumnName,colonna.DataType);
}
fileDestinazione.Append("</tr>");

// poi inserisce i valori nelle righe
foreach(DataRow riga in tabella.Rows)
{
  fileDestinazione.Append("<tr>");

  // .. utilizzando la hashtable delle colonne
  // per stabilire il tipo e la relativa formattazione
  foreach(string NomeColonna in Colonne.Keys)
    fileDestinazione.Append("<td class=""+Colonne[NomeColonna].ToString()+"">"+riga[NomeColonna]+"</td>");

  fileDestinazione.Append("</tr>");
}

// inserisce i tag finali
fileDestinazione.Append("</table></body></html>");

...

Una volta generato il file possiamo salvarlo con il metodo SalvaFile(), richiamarlo con un link e lasciare che l'utente lo scarichi.

Considerazioni finali

Un metodo molto semplice, se volgiamo anche sbrigativo e non attualissimo, ma con molti punti a suo favore.

Una prima considerazione interessante è che lo stesso modello di lavoro possiamo applicarlo banalmente al più attuale markup OpenDocument (anche se questo "vecchio" formato rimane compatibile con moltissime versioni di Excel).

È chiaro che risulta più macchinoso rispetto all'utilizzo dei PIA, che però necessitano di installazione (pensiamo ad applicazioni in Hosting) e di un esborso per la licenza.

Inoltre può darci l'ispirazione per implementare una soluzione simile su piattaforme diverse come PHP, o Ruby.

Ti consigliamo anche