/// <summary> /// Convierte el contenido de un archivo de Excel en una lista de objectos usando un parseador de XML. /// Asume que cada hoja en el archivo de Excel representa a un objecto y que la primera fila de cada /// hoja contiene las columnas que describen las propiedades del objeto. También asume que los nombres /// de las columnas no se repiten. En caso de repetirse el nombre de alguna columna solo se guardará en /// el objeto una sola vez. /// También se da por sentado que todos los datos en una columna a excepción del encabezado son del /// mismo tipo. /// </summary> /// <exception cref="System.IO.IOException">Excepción lanzada cuando el archivo de Excel /// está siendo usado por otro proceso.</exception> public static List<List<Object>> ConvertExcelArchiveToListObjectsSAXApproach(string filePath) { List<List<Object>> listObjects = new List<List<Object>>(); using (SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Open(filePath, false)) { WorkbookPart wbPart = spreadsheetDocument.WorkbookPart; Sheets theSheets = wbPart.Workbook.Sheets; SharedStringTablePart sstPart = spreadsheetDocument.WorkbookPart.GetPartsOfType<SharedStringTablePart>().FirstOrDefault(); SharedStringTable ssTable = null; if (sstPart != null) ssTable = sstPart.SharedStringTable; // Obtiene el formato de celdas para las celdas sin tipos de datos definidos. WorkbookStylesPart workbookStylesPart = spreadsheetDocument.WorkbookPart.GetPartsOfType<WorkbookStylesPart>().First(); CellFormats cellFormats = (CellFormats)workbookStylesPart.Stylesheet.CellFormats; var sheets = wbPart.Workbook.Sheets.Cast<Sheet>().ToList(); foreach (WorksheetPart worksheetpart in wbPart.WorksheetParts) { OpenXmlPartReader reader = new OpenXmlPartReader(worksheetpart); List<String> columnValues = new List<String>(); Cell c; var value = string.Empty; string partRelationshipId = wbPart.GetIdOfPart(worksheetpart); var correspondingSheet = sheets.FirstOrDefault( s => s.Id.HasValue && s.Id.Value == partRelationshipId); string sheetName = string.Empty; // Obtiene el nombre de la hoja de Excel if (correspondingSheet != null) { sheetName = correspondingSheet.GetAttribute("name", "").Value; } if (sheetName == string.Empty) { sheetName = "MyDynamicType"; } // Crea un ensamblado dinámico y un módulo. AssemblyName assemblyName = new AssemblyName(); assemblyName.Name = "tmpAssembly"; AssemblyBuilder assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); ModuleBuilder module = assemblyBuilder.DefineDynamicModule("tmpModule"); // Crea un nuevo constructor de tipos. TypeBuilder typeBuilder = module.DefineType(sheetName, TypeAttributes.Public | TypeAttributes.Class); MethodAttributes GetSetAttr = MethodAttributes.Public | MethodAttributes.HideBySig; int numberOfColumns = 0; bool firstRowInformation = false; while (reader.Read()) { if (reader.ElementType == typeof(SheetData)) { // Obtiene la primera fila. // Asume que no hay celdas en blanco entre las columnas con información. // Si hay columnas vacias no serán agregadas. reader.ReadFirstChild(); if (reader.ElementType == typeof(Row)) { reader.ReadFirstChild(); do { if (reader.ElementType == typeof(Cell)) { c = (Cell)reader.LoadCurrentElement(); if (c.DataType != null && c.DataType.HasValue && c.DataType == CellValues.SharedString && int.Parse(c.CellValue.InnerText) < ssTable.ChildElements.Count) { value = ssTable.ChildElements[int.Parse(c.CellValue.InnerText)].InnerText ?? string.Empty; } else { if (c.CellValue != null && c.CellValue.InnerText != null) { value = c.CellValue.InnerText; } else { value = string.Empty; } } if (value != string.Empty) { columnValues.Add(value); ++numberOfColumns; } } } while (reader.ReadNextSibling()); } reader.Read(); foreach (var columnName in columnValues) { // Genera una propiedad pública var field = typeBuilder.DefineField("_" + columnName.ToString(), typeof(String), FieldAttributes.Private); PropertyBuilder property = typeBuilder.DefineProperty(columnName.ToString(), System.Reflection.PropertyAttributes.None, typeof(string), new Type[] { typeof(string) }); // Genera un método para acceder a la propiedad. var getter = typeBuilder.DefineMethod("get_" + columnName.ToString(), GetSetAttr, typeof(String), Type.EmptyTypes); var il = getter.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, field); il.Emit(OpCodes.Ret); property.SetGetMethod(getter); // Genera un método para cambiar el valor de la propiedad. var setter = typeBuilder.DefineMethod("set_" + columnName, GetSetAttr, null, new[] { typeof(string) }); il = setter.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Stfld, field); il.Emit(OpCodes.Ret); property.SetSetMethod(setter); } dynamic expandoObjectClass = new ExpandoObject(); List<Object> listObjectsCustomClasses = new List<Object>(); // Lee el resto de las filas en la hoja de Excel do { if (reader.ElementType == typeof(Row)) { reader.ReadFirstChild(); Type generatedType = typeBuilder.CreateType(); object generatedObject = Activator.CreateInstance(generatedType); PropertyInfo[] properties = generatedType.GetProperties(); int propertiesCounter = 0; // Lee todas las celdas en la fila. if (firstRowInformation == false) { firstRowInformation = true; do { if (reader.ElementType == typeof(Cell)) { c = (Cell)reader.LoadCurrentElement(); if (c.DataType != null && c.DataType.HasValue && c.DataType == CellValues.SharedString && int.Parse(c.CellValue.InnerText) < ssTable.ChildElements.Count) { value = ssTable.ChildElements[int.Parse(c.CellValue.InnerText)].InnerText ?? string.Empty; } else { if (c.CellValue != null && c.CellValue.InnerText != null) { value = c.CellValue.InnerText; } else { value = string.Empty; } } if (propertiesCounter < properties.Count()) { properties[propertiesCounter].SetValue(generatedObject, value, null); } propertiesCounter++; } } while (reader.ReadNextSibling()); } else { do { if (reader.ElementType == typeof(Cell)) { c = (Cell)reader.LoadCurrentElement(); if (c.DataType != null && c.DataType.HasValue && c.DataType == CellValues.SharedString && int.Parse(c.CellValue.InnerText) < ssTable.ChildElements.Count) { value = ssTable.ChildElements[int.Parse(c.CellValue.InnerText)].InnerText ?? string.Empty; } else { if (c.CellValue != null && c.CellValue.InnerText != null) { value = c.CellValue.InnerText; } else { value = string.Empty; } } if (propertiesCounter < properties.Count()) { if (value == string.Empty && properties[propertiesCounter].GetType().Name != "String") { properties[propertiesCounter].SetValue(generatedObject, null, null); } else { properties[propertiesCounter].SetValue(generatedObject, value, null); } } propertiesCounter++; } } while (reader.ReadNextSibling()); } listObjectsCustomClasses.Add(generatedObject); } } while (reader.Read() && reader.ElementType == typeof(Row)); listObjects.Add(listObjectsCustomClasses); } } } } return listObjects; }
public void WriterWithNsTest() { using (var memStream = new MemoryStream()) { using (OpenXmlPartWriter target = new OpenXmlPartWriter(memStream)) { target.WriteStartDocument(); target.WriteStartElement(new Document()); target.WriteStartElement(new Body(), new List<OpenXmlAttribute>() { new OpenXmlAttribute("a:a", "http://aa", "ab") }); target.WriteStartElement(new Paragraph(), null, null); target.WriteEndElement(); List<KeyValuePair<string, string>> ns = new List<KeyValuePair<string, string>>(); KeyValuePair<string, string> item = new KeyValuePair<string, string>("b", "http://aaa"); ns.Add(item); target.WriteStartElement(new Table(), null, ns); target.WriteEndElement(); target.WriteEndElement(); target.WriteEndElement(); target.Close(); } memStream.Flush(); memStream.Seek(0, SeekOrigin.Begin); using (var reader = new OpenXmlPartReader(memStream)) { //<w:document> reader.Read(); Assert.Equal(1, reader.NamespaceDeclarations.Count()); //<w:body> reader.Read(); Assert.Equal(1, reader.NamespaceDeclarations.Count()); //<w:p> reader.ReadFirstChild(); Assert.True(reader.ElementType.Name.EndsWith("Paragraph")); Assert.Equal(0, reader.NamespaceDeclarations.Count()); //<w:p> reader.ReadNextSibling(); Assert.True(reader.ElementType.Name.EndsWith("Table")); Assert.Equal(1, reader.NamespaceDeclarations.Count()); } } }