OpenXml delle mie brame…
Per cominciare è necessario procurarsi l’SDK (al momento della scrittura in versione 2.0 December 2009 CTP) direttamente dal sito Microsoft, una volta installato se non avete mai visto in vita vostra OpenXml e come me siete allergici al manuale delle istruzioni (le specifiche di OpenXml sono qualche migliaio di pagine… e le ho anche lette in parte…) niente paura! L’SDK contiene il tool piu fantasticissimo del mondo, nella directory “tool” dove avete installato l'SDK: OpenXmlSdkTool.exe.
Avviate il robo e provate a caricare un documento, nello screenshot un file di Excel di esempio, il signorino vi esplode sulla sinistra la struttura del file OpenXml e selezionando un nodo è possibile chiedergli (Reflect Code) di produrci il codice C# necessario per produrre quel nodo!
Spettacolo!!! :-)
Con questo tool diventa veramente banale produrre dei documenti che aderiscono alle specfiche OpenXml. Non è altrettanto facile il contrario, cioè leggere un documento perchè è necessario conoscere molto bene il formato e le sue specifiche. Due esempi, giusto per capirci.
Scrittura/Lettura di valori in una cella di Excel
Quando scrivete un valore potete limitarvi a fare:
Questo crea una cella con del testo ed Excel vive felice, se però cercate di leggere una cosa prodotta da Excel, o anche il vostro file dopo averlo modificato con Excel, scoprite che il ragionamento non vale più. Excel, come da specifiche, usa una cosa che si chiama SharedStringTable e linka i valori, che piazza nella tabella condivisa, alle celle. Ergo per leggere un contenuto dovete fare una cosa del tipo:var cell = new Cell( new CellValue( "sample text" ) ) { DataType = CellValues.String };
Perchè tutti quei controlli sui null?String GetCellText( Cell cell ) { var value = String.Empty; if( cell != null && cell.CellValue != null ) { value = cell.CellValue.Text; if( cell.DataType == CellValues.SharedString ) { value = this.stringTable.Descendants<SharedStringItem>().ElementAt( Int32.Parse( cell.CellValue.Text ) ).Text.Text; } value = value.Trim(); } return value; }
La battaglia navale…
Noi siamo abituati a pensare al foglio di calcolo come ad una griglia ma se proviamo a scorrere le celle come se scorressimo gli elementi di una matrice bidimensionale ci troveremmo di fronte a delle interessanti sorprese…
Se:
- provate ad aprire un nuovo foglio di Excel;
- vi posizionate alla cella D12;
- scrivete qualcosa;
Che potete usare così:const string letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; String ParseCellReference( Int32 hCord, Int32 vCord ) { var letter = letters[ hCord ].ToString(); var number = vCord.ToString(); return String.Concat( letter, number ); }
E’ ovvio che ParseCellReference è un po’ semplicistico perchè non tiene conto di colonne oltre la 25esima cosa fattibilissima in Excel ma è giusto un hint :-)var reference = this.ParseCellReference( 3, 12 ); //D12 var cell = row.Elements<Cell>() .Where( c => c.CellReference == reference ) .SingleOrDefault();
.m