Mostrando las entradas con la etiqueta Reflection. Mostrar todas las entradas
Mostrando las entradas con la etiqueta Reflection. Mostrar todas las entradas

lunes, 20 de noviembre de 2017

El Manual del Día: LINQ

MSDN - Manual de LINQ

Titulo: Manual de LINQ
Fuente Original: Microsoft Developer Network (MSDN)
Compilado Por: Luis Dueñas Huaroto (Lduenas)
Año de Compilación: 2008
Número de Páginas: 388


Indice del Manual de LINQ

1. Introducción a LINQ
2. Introducción a LINQ en Visual Basic
  2.1. Escribir la Primera Consulta con LINQ
  2.2. Operaciones Básicas de Consulta
  2.3. Características de Visual Basic que Admiten LINQ
  2.4. Relaciones entre Tipos en Operaciones de Consulta
3. Cómo: Crear un Proyecto con LINQ
4. Características de IDE de Visual Studio y Herramientas para LINQ
5. Guía de Programación General con LINQ
  5.1. Información General sobre Operadores de Consulta Estándar
    5.1.1. Sintaxis de Expresiones de Consulta para Operadores de Consulta Estándar
    5.1.2. Clasificación de Operadores de Consulta Estándar por Modo de Ejecución
    5.1.3. Ordenar Datos
    5.1.4. Operaciones Set
    5.1.5. Filtrar Datos
    5.1.6. Operaciones Cuantificadotas
    5.1.7. Operaciones de Proyección
    5.1.8. Realizar Particiones de Datos
    5.1.9. Operaciones de Combinación
    5.1.10. Agrupar Datos
    5.1.11. Operaciones de Generación
    5.1.12. Operaciones de Igualdad
    5.1.13. Operaciones de Elementos
    5.1.14. Convertir Tipos de Datos
    5.1.15. Operaciones de Concatenación
    5.1.16. Operaciones de Agregación
  5.2. Arboles de Expresión en LINQ
    5.2.1. Cómo: Usar Arboles de Expresión para Crear Consultas Dinámicas
  5.3. Habilitar un Origen de Datos para Realizar Consultas
6. LINQ a Objectos
  6.1. LINQ y Cadenas
    6.1.1. Cómo: Realizar Recuento de las Repeticiones de una Palabra en una Cadena
    6.1.2. Cómo: Buscar Frases que Contengan un Conjunto Especificado de Palabras
    6.1.3. Cómo: Buscar Caracteres en una Cadena
    6.1.4. Cómo: Combinar Consultas LINQ con Expresiones Regulares
    6.1.5. Cómo: Buscar la Diferencia de Conjuntos entre Dos Listas
    6.1.6. Cómo: Ordenar o Filtrar Datos de Texto por Palabra o Campo
    6.1.7. Cómo: Reordenar los Campos de un Archivo Delimitado
    6.1.8. Cómo: Combinar y Comparar Colecciones de Cadenas
    6.1.9. Cómo: Rellenar Colecciones de Objetos de Varios Orígenes
    6.1.10. Cómo: Dividir un Archivo en Varios Archivos Mediante el Uso de Grupos
    6.1.11. Cómo: Combinar Contenido de Archivos No Similares
    6.1.12. Cómo: Calcular Valores de Columna en un Archivo de Texto CSV
  6.2. LINQ y Reflection
    6.2.1. Cómo: Consultar los Metadatos de un Ensamblado con la Función de Reflexión
  6.3. LINQ y Directorios de Archivos
    6.3.1. Cómo: Buscar Archivos con un Nombre o Atributo Especificados
    6.3.2. Cómo: Agrupar Archivos por Extensión
    6.3.3. Cómo: Buscar el Número Total de Bytes en un Conjunto de Carpetas
    6.3.4. Cómo: Comparar el Contenido de dos Carpetas
    6.3.5. Cómo: Buscar el Archivo(s) de Mayor Tamaño en un Arbol de Directorios
    6.3.6. Cómo: Buscar Archivos Duplicados en un Arbol de Directorios
    6.3.7. Cómo: Consultar el Contenido de los Archivos de una Carpeta
  6.4. Cómo: Consultar un Objeto ArrayList con LINQ
7. LINQ a XML
  7.1. Introducción LINQ a XML
    7.1.1. Información General Acerca de LINQ a XML
    7.1.2. Diferencias entre LINQ a XML y DOM
    7.1.3. Diferencias entre LINQ a XML y otras Tecnologías XML
  7.2. Guía de Programación LINQ a XML
    7.2.1. Información General Acerca de la Programación de LINQ a XML
      7.2.1.1. Información General de los Enfoques de Programación LINQ a XML
      7.2.1.2. Información General de las Clases LINQ a XML
      7.2.1.3. Información General Acerca de la Clase XElement
      7.2.1.4. Información General Acerca de la Clase XAttribute
      7.2.1.5. Información General Acerca de la Clase XDocument
      7.2.1.6. Cómo Crear Ejemplos de LINQ a XML
    7.2.2. Crear Arboles XML
      7.2.2.1. Construcción Funcional
      7.2.2.2. Introducción a los Literales XML en Visual Basic
      7.2.2.3. Diferencias entre Agregar y Clonar
      7.2.2.4. Analizar XML
        7.2.2.4.1. Cómo Analizar una Cadena
        7.2.2.4.2. Cómo Cargar XML de un Archivo
        7.2.2.4.3. Conservar Espacios en Blanco mientras se Carga o se Analiza el XML
        7.2.2.4.4. Cómo Detectar Errores de Análisis
        7.2.2.4.5. Cómo Crear un Arbol de XmlReader
        7.2.2.4.6. Cómo Transmitir por Secuencias Fragmentos XML de XmlReader
      7.2.2.5. Cómo Rellenar un Arbol XML Con XmlWriter
      7.2.2.6. Cómo Validar con XSD
      7.2.2.7. Contenido Válido de Objetos XElement y XDocument
    7.2.3. Trabajar con Espacios de Nombres XML
      7.2.3.1. Información General Sobre los Espacios de Nombres
      7.2.3.2. Espacios de Nombres en Visual Basic
        7.2.3.2.1. Cómo Crear un Documento con Espacios de Nombres
        7.2.3.2.2. Cómo Controlar Prefijos de Espacios de Nombres
        7.2.3.2.3. Trabajar con Espacios de Nombres Globales
      7.2.3.3. Cómo Escribir Consultas en XML en Espacios de Nombre
    7.2.4. Serializar Arboles XML
      7.2.4.1. Preservar los Espacios en Blanco durante la Serialización
      7.2.4.2. Serializar con una Declaración XML
      7.2.4.3. Serializar en Archivos, TextWriters y XmlWriters
      7.2.4.4. Serializar en XmlReader (Invocar XSLT)
    7.2.5. Ejes LINQ a XML
      7.2.5.1. Información General Acerca de los Ejes de LINQ a XML
      7.2.5.2. Cómo Recuperar una Recopilación de Elementos
      7.2.5.3. Cómo Recuperar el Valor de un Elemento
      7.2.5.4. Cómo Filtrar Nombres de Elemento
      7.2.5.5. Cómo Encadenar Llamadas a Métodos de Eje
      7.2.5.6. Cómo Recuperar un Unico Elemento Secundario
      7.2.5.7. Cómo Recuperar una Colección de Atributos
      7.2.5.8. Cómo Recuperar un Atributo en Particular
      7.2.5.9. Cómo Recuperar el Valor de un Atributo
      7.2.5.10. Ejes Integrados en el Lenguaje en Visual Basic
    7.2.6. Consultar Arboles XML
      7.2.6.1. Consultas Básicas LINQ a XML
        7.2.6.1.1. Cómo Buscar un Elemento con un Atributo Específico
        7.2.6.1.2. Cómo Buscar un Elemento con un Elemento Secundario Específico
        7.2.6.1.3. Diferencias entre Realizar Consultas de un XDocument y de un Element
        7.2.6.1.4. Cómo Encontrar Descendientes con un Nombre de Elemento Específico                 7.2.6.1.5. Cómo Buscar un Descendiente Unico mediante el Método Descendants
        7.2.6.1.6. Cómo Escribir Consultas con Filtrado Complejo
        7.2.6.1.7. Cómo Filtrar por un Elemento Opcional
        7.2.6.1.8. Cómo Buscar Todos los Nodos en un Espacio de Nombres
        7.2.6.1.9. Cómo Ordenar Elementos
        7.2.6.1.10. Cómo Ordenar Elementos en Varias Claves
        7.2.6.1.11. Cómo Calcular Valores Intermedios
        7.2.6.1.12. Cómo Escribir una Consulta que Busca Elementos Basándose en el Contexto
        7.2.6.1.13. Cómo Depurar Conjuntos de Resultados de Consultas Vacíos
      7.2.6.2. Proyecciones y Transformaciones LINQ a XML
        7.2.6.2.1. Cómo Trabajar con Diccionarios usando LINQ a XML
        7.2.6.2.2. Cómo Transformar la Forma de un Arbol XML
        7.2.6.2.3. Cómo Controlar el Tipo de una Proyección
        7.2.6.2.4. Cómo Proyectar un Nuevo Tipo
        7.2.6.2.5. Cómo Proyectar un Gráfico de Objetos
        7.2.6.2.6. Cómo Proyectar un Tipo Anónimo
        7.2.6.2.7. Cómo Generar Archivos de Texto a partir de XML
        7.2.6.2.8. Cómo Generar un XML a partir de Archivos CSV
      7.2.6.3. Técnicas Avanzadas de Consulta LINQ a XML
        7.2.6.3.1. Cómo Crear una Jerarquía con la Agrupación
        7.2.6.3.2. Cómo Realizar Consultas de LINQ a XML con Xpath
        7.2.6.3.3. Cómo Enumerar Todos los Nodos de un Arbol
        7.2.6.3.4. Cómo Rellenar un Arbol XML a partir del Sistema de Archivos
      7.2.6.4. LINQ a XML para usuarios de Xpath
        7.2.6.4.1. Comparación de XPath y LINQ a XML
        7.2.6.4.2. Cómo Buscar un Elemento Secundario
        7.2.6.4.3. Cómo Buscar una Lista de Elementos Secundarios
        7.2.6.4.4. Cómo Buscar el Elemento Raíz
        7.2.6.4.5. Cómo Buscar Elementos Descendientes
        7.2.6.4.6. Cómo Filtrar por Atributo
        7.2.6.4.7. Cómo Buscar Elementos Relacionados
        7.2.6.4.8. Cómo Buscar Elementos en un Espacio de Nombres
        7.2.6.4.9. Cómo Encontrar Elementos Relacionados Anteriores
        7.2.6.4.10. Cómo Buscar Descendientes de un Elemento Secundario
        7.2.6.4.11. Cómo Buscar una Unión de dos Rutas de Ubicación
        7.2.6.4.12. Cómo Buscar Nodos Relacionados
        7.2.6.4.13. Cómo Buscar un Atributo del Elemento Primario
        7.2.6.4.14. Cómo Buscar Atributos de Elementos Secundarios con un Nombre Específico         7.2.6.4.15. Cómo Buscar Elementos que Tienen un Atributo Especifico
        7.2.6.4.16. Cómo Buscar Elementos Secundarios en base a la Posición
        7.2.6.4.17. Cómo Buscar el Elemento del Mismo Nivel Inmediatamente Anterior
    7.2.7. Modificar Arboles XML
      7.2.7.1. Diferencias Entre la Modificación del Arbol XML en Memoria y la Construcción Funcional
      7.2.7.2. Agregar Elementos, Atributos y Nodos a un Arbol XML
      7.2.7.3. Modificar Elementos, Atributos y Nodos en un Arbol XML
      7.2.7.4. Quitar Elementos, Atributos y Nodos de un Arbol XML
      7.2.7.5. Mantener los Pares Nombre/Valor
      7.2.7.6. Cómo Cambiar el Espacio de Nombres de un Arbol XML Completo
    7.2.8. Programación Avanzada de LINQ a XML
      7.2.8.1. Anotaciones en LINQ a XML
      7.2.8.2. Eventos de LINQ a XML
      7.2.8.3. Programar con Nodos
      7.2.8.4. Cómo Leer y Escribir un Documento Codificado
      7.2.8.5. Usar XSLT para Transformar un Arbol XML
    7.2.9. Seguridad de LINQ a XML
8. LINQ a ADO .NET
  8.1. Información General de LINQ a ADO .NET
  8.2. LINQ a DataSet
    8.2.1. Introducción LINQ a DataSet
      8.2.1.1. Información General de LINQ a DataSet
      8.2.1.2. Cargar Datos en un DataSet
      8.2.1.3. Cómo crear un Proyecto LINQ a DataSet en Visual Studio
    8.2.2. Guía de Programación LINQ a DataSet
      8.2.2.1. Consultas en LINQ a DataSet
      8.2.2.2. Consultar DataSets
        8.2.2.2.1. Consultas de Tabla Unica
        8.2.2.2.2. Consultas Entre Tablas
        8.2.2.2.3. Consultar DataSets con Establecimiento de Tipos
      8.2.2.3. Comparar DataRows
      8.2.2.4. Crear DataTable desde una Consulta
      8.2.2.5. Métodos Genéricos Field y SetField
      8.2.2.6. Enlace de Datos y LINQ a DataSet
        8.2.2.6.1. Crear un Objeto DataView
        8.2.2.6.2. Filtrar con DataView
        8.2.2.6.3. Ordenar con DataView
        8.2.2.6.4. Rendimiento del DataView
        8.2.2.6.5. Cómo Enlazar un Objeto DataView al Control DataGridView de Windows Forms
      8.2.2.7. Depurar Consultas LINQ a DataSet
      8.2.2.8. Seguridad
      8.2.2.9. Ejemplos de LINQ a DataSet
        8.2.2.9.1. Ejemplos de Sintaxis de Expresiones de Consulta
          8.2.2.9.1.1. Proyección
          8.2.2.9.1.2. Restricción
          8.2.2.9.1.3. Creación de Particiones
          8.2.2.9.1.4. Ordenación
          8.2.2.9.1.5. Operadores de Elementos
          8.2.2.9.1.6. Operadores de Agregado
          8.2.2.9.1.7. Operadores de Combinación
        8.2.2.9.2. Ejemplos de Sintaxis de Consulta Basada en Métodos
          8.2.2.9.2.1. Proyección
          8.2.2.9.2.2. Creación de Particiones
          8.2.2.9.2.3. Ordenación
          8.2.2.9.2.4. Operadores de Conjuntos
          8.2.2.9.2.5. Operadores de Conversión
          8.2.2.9.2.6. Operadores de Elementos
          8.2.2.9.2.7. Operadores de Agregado
          8.2.2.9.2.8. Combinación
        8.2.2.9.3. Ejemplos de Operadores Específicos de DataSet
  8.3. LINQ a SQL
    8.3.1. Introducción LINQ a SQL
      8.3.1.1. Qué se Puede Hacer con LINQ a SQL
      8.3.1.2. Procedimientos Típicos para Usar LINQ a SQL
    8.3.2. Guía de Programación LINQ a SQL
      8.3.2.1. Crear el Modelo de Objetos
        8.3.2.1.1. Cómo: Generar el Modelo de Objetos en Visual Basic o C#
        8.3.2.1.2. Cómo: Generar el Modelo de Objetos como un Archivo Externo
        8.3.2.1.3. Cómo: Generar Código Personalizado Mediante la Modificación de un Archivo DBML
        8.3.2.1.4. Cómo: Validar Archivos de Asignación Externa y DBML
        8.3.2.1.5. Cómo: Convertir Entidades en Serializables
        8.3.2.1.6. Cómo: Personalizar Clases de Entidad Mediante el Editor de Código
          8.3.2.1.6.1. Cómo: Especificar Nombres de Base de Datos
          8.3.2.1.6.2. Cómo: Representar Tablas como Clases
          8.3.2.1.6.3. Cómo: Representar Columnas como Miembros de Clase
          8.3.2.1.6.4. Cómo: Representar Claves Principales
          8.3.2.1.6.5. Cómo: Asignar Relaciones de Base de Datos
          8.3.2.1.6.6. Cómo: Representar Columnas como Generadas por la Base de Datos
          8.3.2.1.6.7. Cómo: Representar Columnas como Columnas de Marca de Tiempo o Versión
          8.3.2.1.6.8. Cómo: Especificar Tipos de Datos de una Base de Datos
          8.3.2.1.6.9. Cómo: Representar Columnas Calculadas
          8.3.2.1.6.10. Cómo: Especificar Campos de Almacenamiento Privado
          8.3.2.1.6.11. Cómo: Representar Columnas que Permitan Valores Null
          8.3.2.1.6.12. Cómo: Asignar Jerarquías de Herencia
          8.3.2.1.6.13. Cómo: Especificar la Comprobación de Conflictos de Simultaneidad
      8.3.2.2. Comunicar con la Base de Datos
        8.3.2.2.1. Cómo: Conectarse a una Base de Datos
        8.3.2.2.2. Cómo: Ejecutar Directamente Comandos SQL
        8.3.2.2.3. Cómo: Volver a Usar una Conexión entre un Comando ADO.NET y DataContext

Descarga

lunes, 26 de septiembre de 2016

El Libro del Día: Understanding ECMAScript 6

El Libro del Día: 2016-09-26

Titulo: Understanding ECMAScript 6
Autor: Nicholas C. Zakas
Editorial: No Starch Press
Nro Paginas: 355

Capítulos:
Chapter 1: Block Bindings
Chapter 2: Strings and Regular Expressions
Chapter 3: Functions
Chapter 4: Expanded Object Functionality
Chapter 5: Destructuring for Easier Data Access
Chapter 6: Symbols and Symbol Properties
Chapter 7: Sets and Maps
Chapter 8: Iterators and Generators
Chapter 9: Introducing JavaScript Classes
Chapter 10: Improved Array Capabilities
Chapter 11: Promises and Asynchronous Programming
Chapter 12: Proxies and the Reflection API
Chapter 13: Encapsulating Code with Modules
Appendix A: Minor Changes in ECMAScript 6
Appendix B: Understanding ECMAScript 7 (2016)

Descarga:
Understanding_ECMAScript_6

martes, 9 de agosto de 2016

El Demo del Día: Exportar a Excel 2007 desde Listas y Tablas usando XML

Exportar a Excel 2007 desde Listas y Tablas usando XML

1. Introducción

En el post anterior vimos las 3 técnicas que hay para crear un archivo de Excel 2007 exportando datos desde varias listas de objetos o varias tablas de un DataSet en .NET. En ese post se presentó un Demo de cómo usar OLEDB para crear el archivo Excel.

En este post vamos a ver algo inédito, que no hay en la web, que es como crear un archivo de Excel 2007, creando los archivos XML necesarios y luego comprimiendolo en un xlsx.

2. Ventajas de Crear un Archivo Excel usando XML

Existen muchas ventajas de usar esta técnica entre las 3 mas importantes tenemos:

- Es la más rápida en la creación de archivos Excel, casi 3 veces más rápida que OLEDB y mas de 10 veces más rápida que abrir una instancia de Excel (Automatización COM).

- No necesita tener instalado ni los Componentes de Acceso a Datos del "Microsoft Access Database Engine 2010 Redistributable" ni tampoco una instancia de Excel para crear el archivo.

Nota: Ni siquiera se necesita tener instalado el Excel para leer o ver el archivo ya que se puede hacer usando los Visores de los Demos pasados.

- Se puede crear no solo celdas con datos sino gráficos, dar estilo, formatos, etc, cosa que no se puede al usar OLEDB.

Nota: Si se puede abriendo una instancia de Excel pero se demora demasiado y consume muchos recursos, lo cual está terminantemente prohibido para Aplicaciones Web ASP.NET.

3. Crear una Aplicación Windows Forms en C#

Abrir Visual Studio y crear una aplicación Windows Forms en C# llamada "Excel_Crear_XML", cambiarle de nombre al formulario por "frmExcel" y realizar el diseño similar a la figura mostrada:

Diseño del formulario "frmExcel"

En el diseño hay los siguientes controles:
- Botón para Llenar desde Listas llamado "btnLlenarLista".
- Botón para Llenar desde Tablas llamado "btnLlenarTabla".
- Botón para Exportar Listas a Excel llamado "btnExportarListas". Deshabilitado por defecto.
- Botón para Exportar Tablas a Excel llamado "btnExportarTablas". Deshabilitado por defecto.
- Control Tab llamado "tabExcel" con 2 tabPages: "tabCategorias" y "tabProducto".
- Control DataGridView llamado "dgvCategoria" ubicado en el tab de Categorias.
- Control DataGridView llamado "dgvProducto" ubicado en el tab de Productos.

4. Crear las Clases con las Entidades de Negocio

Lo primero que debemos crear son las clases de entidades para las listas de objetos de categorías y productos:

Archivo de Clase: beCategoria.cs

namespace Excel_Crear_XML
{
    public class beCategoria
    {
        public int IdCategoria { get; set; }
        public string Nombre { get; set; }
    }
}

Archivo de Clase: beProducto.cs

namespace Excel_Crear_XML
{
    public class beProducto
    {
        public int IdProducto { get; set; }
        public string Nombre { get; set; }
        public int IdCategoria { get; set; }
        public decimal Precio { get; set; }
        public short Stock { get; set; }
    }
}

Archivo de Clase: beCategoriaProducto.cs

using System.Collections.Generic;

namespace Excel_Crear_XML
{
    public class beCategoriaProducto
    {
        public List<beCategoria> ListaCategoria { get; set; }
        public List<beProducto> ListaProducto { get; set; }
    }
}

5. Crear una Clase que permita llenar los Datos

Lo segundo que debemos hacer es crear una clase para llenar los datos de las tablas y listas de objetos tanto para categorías como productos.

En una aplicación real esto se reemplazará por la llamada a un componente de reglas del negocio y solo se elegirá uno de las 2 repositorios de datos: DataSet o Objeto con Listas. Lo recomendable es elegir el Objeto con Listas ya que consume menos memoria y procesa más rápido.

Archivo de Clase: Data.cs

using System;
using System.Collections.Generic;
using System.Data;

namespace Excel_Crear_XML
{
    public class Data
    {
        public static List<beCategoria> ListaCategorias()
        {
            //Llenar la Lista de Categorias
            List<beCategoria> lbeCategoria = new List<beCategoria>();
            lbeCategoria.Add(new beCategoria
            {
                IdCategoria = 1,
                Nombre = "Bebidas"
            });
            lbeCategoria.Add(new beCategoria
            {
                IdCategoria = 2,
                Nombre = "Cereales"
            });
            lbeCategoria.Add(new beCategoria
            {
                IdCategoria = 3,
                Nombre = "Condimentos"
            });
            lbeCategoria.Add(new beCategoria
            {
                IdCategoria = 4,
                Nombre = "Lacteos"
            });
            lbeCategoria.Add(new beCategoria
            {
                IdCategoria = 5,
                Nombre = "Pastas"
            });
            return lbeCategoria;
        }

        public static List<beProducto> ListaProductos()
        {
            //Llenar la Lista de Productos
            List<beProducto> lbeProducto = new List<beProducto>();
            lbeProducto.Add(new beProducto
            {
                IdProducto = 1,
                Nombre = "Pepsi",
                IdCategoria = 1,
                Precio = 1.5M,
                Stock = 100
            });
            lbeProducto.Add(new beProducto
            {
                IdProducto = 2,
                Nombre = "Avena 3 Ositos",
                IdCategoria = 2,
                Precio = 2.0M,
                Stock = 50
            });
            lbeProducto.Add(new beProducto
            {
                IdProducto = 3,
                Nombre = "Ajinomoto",
                IdCategoria = 3,
                Precio = 0.5M,
                Stock = 200
            });
            lbeProducto.Add(new beProducto
            {
                IdProducto = 4,
                Nombre = "Leche Gloria",
                IdCategoria = 4,
                Precio = 3.5M,
                Stock = 300
            });
            lbeProducto.Add(new beProducto
            {
                IdProducto = 5,
                Nombre = "Fideos Lavaggi",
                IdCategoria = 5,
                Precio = 3.0M,
                Stock = 150
            });
            lbeProducto.Add(new beProducto
            {
                IdProducto = 6,
                Nombre = "Sprite",
                IdCategoria = 1,
                Precio = 2.0M,
                Stock = 200
            });
            lbeProducto.Add(new beProducto
            {
                IdProducto = 7,
                Nombre = "Quinua Avena",
                IdCategoria = 2,
                Precio = 2.5M,
                Stock = 150
            });
            lbeProducto.Add(new beProducto
            {
                IdProducto = 8,
                Nombre = "Tuco Sibarita",
                IdCategoria = 3,
                Precio = 0.5M,
                Stock = 200
            });
            lbeProducto.Add(new beProducto
            {
                IdProducto = 9,
                Nombre = "Leche Pura Vida",
                IdCategoria = 4,
                Precio = 3.5M,
                Stock = 300
            });
            lbeProducto.Add(new beProducto
            {
                IdProducto = 10,
                Nombre = "Spagetti Don Victorio",
                IdCategoria = 5,
                Precio = 2.0M,
                Stock = 250
            });
            return lbeProducto;
        }

        public static DataTable TablaCategorias()
        {
            //Llenar la Tabla de Categorias
            DataTable tblCategoria = new DataTable();
            tblCategoria.Columns.Add("IdCategoria",
                Type.GetType("System.Int32"));
            tblCategoria.Columns.Add("Nombre",
                Type.GetType("System.String"));
            DataRow drCat1 = tblCategoria.NewRow();
            drCat1[0] = 1;
            drCat1[1] = "Bebidas";
            tblCategoria.Rows.Add(drCat1);
            DataRow drCat2 = tblCategoria.NewRow();
            drCat2[0] = 2;
            drCat2[1] = "Cereales";
            tblCategoria.Rows.Add(drCat2);
            DataRow drCat3 = tblCategoria.NewRow();
            drCat3[0] = 3;
            drCat3[1] = "Condimentos";
            tblCategoria.Rows.Add(drCat3);
            DataRow drCat4 = tblCategoria.NewRow();
            drCat4[0] = 4;
            drCat4[1] = "Lacteos";
            tblCategoria.Rows.Add(drCat4);
            DataRow drCat5 = tblCategoria.NewRow();
            drCat5[0] = 5;
            drCat5[1] = "Pastas";
            tblCategoria.Rows.Add(drCat5);
            return tblCategoria;
        }

        public static DataTable TablaProductos()
        {
            //Llenar la Tabla de Productos
            DataTable tblProducto = new DataTable();
            tblProducto.Columns.Add("IdProducto",
                Type.GetType("System.Int32"));
            tblProducto.Columns.Add("Nombre",
                Type.GetType("System.String"));
            tblProducto.Columns.Add("IdCategoria",
                Type.GetType("System.Int32"));
            tblProducto.Columns.Add("Precio",
                Type.GetType("System.Decimal"));
            tblProducto.Columns.Add("Stock",
                Type.GetType("System.Int16"));
            DataRow drPro1 = tblProducto.NewRow();
            drPro1[0] = 1;
            drPro1[1] = "Pepsi";
            drPro1[2] = 1;
            drPro1[3] = 1.5M;
            drPro1[4] = 100;
            tblProducto.Rows.Add(drPro1);
            DataRow drPro2 = tblProducto.NewRow();
            drPro2[0] = 2;
            drPro2[1] = "Avena 3 Ositos";
            drPro2[2] = 2;
            drPro2[3] = 2.0M;
            drPro2[4] = 50;
            tblProducto.Rows.Add(drPro2);
            DataRow drPro3 = tblProducto.NewRow();
            drPro3[0] = 3;
            drPro3[1] = "Ajinomoto";
            drPro3[2] = 3;
            drPro3[3] = 0.5M;
            drPro3[4] = 200;
            tblProducto.Rows.Add(drPro3);
            DataRow drPro4 = tblProducto.NewRow();
            drPro4[0] = 4;
            drPro4[1] = "Leche Gloria";
            drPro4[2] = 4;
            drPro4[3] = 3.5M;
            drPro4[4] = 300;
            tblProducto.Rows.Add(drPro4);
            DataRow drPro5 = tblProducto.NewRow();
            drPro5[0] = 5;
            drPro5[1] = "Fideos Lavaggi";
            drPro5[2] = 5;
            drPro5[3] = 3.0M;
            drPro5[4] = 150;
            tblProducto.Rows.Add(drPro5);
            DataRow drPro6 = tblProducto.NewRow();
            drPro6[0] = 6;
            drPro6[1] = "Sprite";
            drPro6[2] = 1;
            drPro6[3] = 2.0M;
            drPro6[4] = 200;
            tblProducto.Rows.Add(drPro6);
            DataRow drPro7 = tblProducto.NewRow();
            drPro7[0] = 7;
            drPro7[1] = "Quinua Avena";
            drPro7[2] = 2;
            drPro7[3] = 2.5M;
            drPro7[4] = 150;
            tblProducto.Rows.Add(drPro7);
            DataRow drPro8 = tblProducto.NewRow();
            drPro8[0] = 8;
            drPro8[1] = "Tuco Sibarita";
            drPro8[2] = 3;
            drPro8[3] = 0.5M;
            drPro8[4] = 200;
            tblProducto.Rows.Add(drPro8);
            DataRow drPro9 = tblProducto.NewRow();
            drPro9[0] = 9;
            drPro9[1] = "Leche Pura Vida";
            drPro9[2] = 4;
            drPro9[3] = 3.5M;
            drPro9[4] = 200;
            tblProducto.Rows.Add(drPro9);
            DataRow drPro10 = tblProducto.NewRow();
            drPro10[0] = 10;
            drPro10[1] = "Spagetti Don Victorio";
            drPro10[2] = 5;
            drPro10[3] = 2.0M;
            drPro10[4] = 250;
            tblProducto.Rows.Add(drPro10);
            return tblProducto;
        }
    }
}

6. Crear una Clase que permita Crear Archivos XML y Comprimirlos

La tercera parte a codificar es crear una clase que permita crear los diferentes archivos XML necesitados y luego comprimirlos en un archivo XLSX.

Archivo de Clase: Excel.cs

using System;
using System.IO;
using System.Data;
using System.Text;
using System.Reflection;
using System.Linq;
using System.Collections.Generic;
using System.IO.Compression;

namespace Excel_Crear_XML
{
    public class Excel
    {
        private enum TipoOrigen {
            Listas = 0,
            Tablas =1
        }
        private static string sArchivoXlsx;
        private static string[] sHojas;
        private static string[] sRango;
        private static int nHojas;
        private static TipoOrigen tipoOrigen;
        private static List<dynamic> data;

        public static void ExportarDeLista<T>(string archivoXlsx, string[] hojas, T objData)
        {
            data = new List<dynamic>();
            tipoOrigen = TipoOrigen.Listas;
            sArchivoXlsx = archivoXlsx;
            sHojas = hojas;
            nHojas = hojas.Length;
            sRango = new string[nHojas];
            PropertyInfo[] listas = objData.GetType().GetProperties();
            dynamic lista;
            PropertyInfo[] campos;
            for (int i = 0; i < listas.Length;i++)
            {
                lista = listas[i].GetValue(objData, null);
                data.Add(lista);
                campos = lista[0].GetType().GetProperties();
                sRango[i] = String.Format("${0}${1}", (char)(64 + campos.Length), lista.Count + 1);
            }
            crearDirectoriosArchivos();
        }

        public static void ExportarDeTabla(string archivoXlsx, string[] hojas, DataSet objData)
        {
            data = new List<dynamic>();
            tipoOrigen = TipoOrigen.Tablas;
            sArchivoXlsx = archivoXlsx;
            sHojas = hojas;
            nHojas = hojas.Length;
            sRango = new string[nHojas];
            DataTable tabla;
            for (int i = 0; i < objData.Tables.Count; i++)
            {
                tabla = objData.Tables[i];
                data.Add(tabla);
                sRango[i] = String.Format("${0}${1}",
                (char)(64 + tabla.Columns.Count), tabla.Rows.Count + 1);
            }
            crearDirectoriosArchivos();
        }

        private static void crearDirectoriosArchivos()
        {
            //Definir la ruta de los directorios a crear
            string sDirectorioRaiz = Path.Combine(Path.GetDirectoryName(sArchivoXlsx),
                Path.GetFileNameWithoutExtension(sArchivoXlsx));
            string sDirectorioRels = Path.Combine(sDirectorioRaiz, "_rels");
            string sDirectorioDocProps = Path.Combine(sDirectorioRaiz, "docProps");
            string sDirectorioXl = Path.Combine(sDirectorioRaiz, "xl");
            string sDirectorioXlRels = Path.Combine(sDirectorioXl, "_rels");
            string sDirectorioXlTheme = Path.Combine(sDirectorioXl, "theme");
            string sDirectorioXlWorksheets = Path.Combine(sDirectorioXl, "worksheets");

            //Definir la ruta de los archivos a crear
            string sArchivoContentTypes = Path.Combine(sDirectorioRaiz, "[Content_Types].xml");
            string sArchivoRels = Path.Combine(sDirectorioRels, ".rels");
            string sArchivoDocApp = Path.Combine(sDirectorioDocProps, "app.xml");
            string sArchivoDocCore = Path.Combine(sDirectorioDocProps, "core.xml");
            string sArchivoXlStyles = Path.Combine(sDirectorioXl, "styles.xml");
            string sArchivoXlWorkbook = Path.Combine(sDirectorioXl, "workbook.xml");
            string sArchivoXlRels = Path.Combine(sDirectorioXlRels, "workbook.xml.rels");
            string sArchivoXlTheme = Path.Combine(sDirectorioXlTheme, "theme1.xml");
            string[] sArchivoXlSheets = new string[nHojas];
            for (var i = 0; i < nHojas;i++) sArchivoXlSheets[i] =
                Path.Combine(sDirectorioXlWorksheets, String.Format("sheet{0}.xml",i+1));
         
            //Crear los Directorios definidos
            DirectoryInfo oDirectorioRaiz = Directory.CreateDirectory(sDirectorioRaiz);
            oDirectorioRaiz.CreateSubdirectory("_rels");
            oDirectorioRaiz.CreateSubdirectory("docProps");
            DirectoryInfo oDirectorioXl = oDirectorioRaiz.CreateSubdirectory("xl");
            oDirectorioXl.CreateSubdirectory("_rels");
            oDirectorioXl.CreateSubdirectory("theme");
            oDirectorioXl.CreateSubdirectory("worksheets");

            //Crear los Archivos definidos
            File.WriteAllText(sArchivoContentTypes, getContentTypes());
            File.WriteAllText(sArchivoRels, getRels());
            File.WriteAllText(sArchivoDocApp, getApp());
            File.WriteAllText(sArchivoDocCore, getCore());
            File.WriteAllText(sArchivoXlStyles, getXlStyles());
            File.WriteAllText(sArchivoXlWorkbook, getXlWorkbook());
            File.WriteAllText(sArchivoXlRels, getXlRels());
            File.WriteAllText(sArchivoXlTheme, getXlTheme());
            for (var i = 0; i < nHojas; i++) File.WriteAllText(sArchivoXlSheets[i], getXlSheet(i));

            //Comprimir los archivos en un Xlsx
            ZipFile.CreateFromDirectory(sDirectorioRaiz, sArchivoXlsx);
            //Borrar todo el directorio con los archivos temporales creados
            Directory.Delete(sDirectorioRaiz, true);
        }

        private static string getContentTypes()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>");
            sb.Append("<Types xmlns=\"http://schemas.openxmlformats.org/
            package/2006/content-types\">");
            sb.Append("<Default Extension=\"rels\" ContentType=
            \"application/vnd.openxmlformats-package.relationships+xml\"/>");
            //sb.Append("<Default Extension=\"wmf\" ContentType=\"image/x-wmf\"/>");
            sb.Append("<Default Extension=\"xml\" ContentType=\"application/xml\"/>");
            sb.Append("<Override PartName=\"/xl/workbook.xml\" ContentType=
            \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml\"/>");
            sb.Append("<Override PartName=\"/xl/styles.xml\" ContentType=
            \"application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml\"/>");
            sb.Append("<Override PartName=\"/xl/theme/theme1.xml\" ContentType=
            \"application/vnd.openxmlformats-officedocument.theme+xml\"/>");
            sb.Append("<Override PartName=\"/docProps/core.xml\" ContentType=
            \"application/vnd.openxmlformats-package.core-properties+xml\"/>");
            sb.Append("<Override PartName=\"/docProps/app.xml\" ContentType=
            \"application/vnd.openxmlformats-officedocument.extended-properties+xml\"/>");
            for (var i = 0; i < nHojas; i++)
            {
                sb.Append("<Override PartName=\"/xl/worksheets/sheet");
                sb.Append(i + 1);
                sb.Append(".xml\" ContentType=\"application/vnd.openxmlformats-officedocument.
                spreadsheetml.worksheet+xml\"/>");
            }
            sb.Append("</Types>");
            return sb.ToString();
        }

        private static string getRels()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>");
            sb.Append("<Relationships xmlns=\"http://schemas.openxmlformats.org/
            package/2006/relationships\">");
            sb.Append("<Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/
            package/2006/relationships/metadata/core-properties\" Target=\"docProps/core.xml\"/>");
            //sb.Append("<Relationship Id=\"rId2\" Type=\"http://schemas.openxmlformats.org/
            package/2006/relationships/metadata/thumbnail\" Target=\"docProps/thumbnail.wmf\"/>");
            sb.Append("<Relationship Id=\"rId2\" Type=\"http://schemas.openxmlformats.org/
            officeDocument/2006/relationships/officeDocument\" Target=\"xl/workbook.xml\"/>");
            sb.Append("<Relationship Id=\"rId3\" Type=\"http://schemas.openxmlformats.org/
            officeDocument/2006/relationships/extended-properties\"
            Target=\"docProps/app.xml\"/>");
            sb.Append("</Relationships>");
            return sb.ToString();
        }

        private static string getApp()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>");
            sb.Append("<Properties xmlns=\"http://schemas.openxmlformats.org/
            officeDocument/2006/extended-properties\"
            xmlns:vt=\"http://schemas.openxmlformats.org/
            officeDocument/2006/docPropsVTypes\">");
            sb.Append("<Application>Microsoft Access</Application>");
            sb.Append("<DocSecurity>0</DocSecurity>");
            sb.Append("<ScaleCrop>false</ScaleCrop>");
            sb.Append("<HeadingPairs>");
            sb.Append("<vt:vector size=\"2\" baseType=\"variant\">");
            sb.Append("<vt:variant><vt:lpstr>Worksheets</vt:lpstr></vt:variant>");
            sb.Append("<vt:variant><vt:i4>1</vt:i4></vt:variant>");
            sb.Append("</vt:vector>");
            sb.Append("</HeadingPairs>");
            sb.Append("<TitlesOfParts>");
            sb.Append("<vt:vector size=\"1\" baseType=\"lpstr\">");
            sb.Append("<vt:lpstr>A266FF2A662E84b639DA</vt:lpstr>");
            sb.Append("</vt:vector>");
            sb.Append("</TitlesOfParts>");
            sb.Append("<Company>Microsoft</Company>");
            sb.Append("<LinksUpToDate>false</LinksUpToDate>");
            sb.Append("<SharedDoc>false</SharedDoc>");
            sb.Append("<HyperlinksChanged>false</HyperlinksChanged>");
            sb.Append("<AppVersion>12.0000</AppVersion>");
            sb.Append("</Properties>");
            return sb.ToString();
        }

        private static string getCore()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>");
            sb.Append("<cp:coreProperties ");
            sb.Append("xmlns:cp=\"http://schemas.openxmlformats.org/package/2006/metadata/
            core-properties\" ");
            sb.Append("xmlns:dc=\"http://purl.org/dc/elements/1.1/\" ");
            sb.Append("xmlns:dcterms=\"http://purl.org/dc/terms/\" ");
            sb.Append("xmlns:dcmitype=\"http://purl.org/dc/dcmitype/\" ");
            sb.Append("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">");
            sb.Append("<dc:creator>");
            sb.Append(Environment.UserName);
            sb.Append("</dc:creator>");
            sb.Append("<cp:lastModifiedBy>");
            sb.Append(Environment.UserName);
            sb.Append("</cp:lastModifiedBy>");
            sb.Append("<dcterms:created xsi:type=\"dcterms:W3CDTF\">");
            sb.Append(DateTime.Now.ToString("s"));
            sb.Append("Z</dcterms:created>");
            sb.Append("<dcterms:modified xsi:type=\"dcterms:W3CDTF\">");
            sb.Append(DateTime.Now.ToString("s"));
            sb.Append("Z</dcterms:modified>");
            sb.Append("</cp:coreProperties>");          
            return sb.ToString();
        }

        private static string getXlStyles()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("<styleSheet xmlns=\"http://schemas.openxmlformats.org/
            spreadsheetml/2006/main\">");
            sb.Append("<fonts count=\"1\">");
            sb.Append("<font>");
            sb.Append("<sz val=\"11\"/>");
            sb.Append("<color theme=\"1\"/>");
            sb.Append("<name val=\"MS Sans Serif\"/>");
            sb.Append("<family val=\"2\"/>");
            sb.Append("<scheme val=\"minor\"/>");
            sb.Append("</font>");
            sb.Append("</fonts>");
            sb.Append("<fills count=\"2\">");
            sb.Append("<fill><patternFill patternType=\"none\"/></fill>");
            sb.Append("<fill><patternFill patternType=\"gray125\"/></fill>");
            sb.Append("</fills>");
            sb.Append("<borders count=\"1\">");
            sb.Append("<border><left/><right/><top/><bottom/><diagonal/></border>");
            sb.Append("</borders>");
            sb.Append("<cellStyleXfs count=\"1\">");
            sb.Append("<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\"/>");
            sb.Append("</cellStyleXfs>");
            sb.Append("<cellXfs count=\"1\">");
            sb.Append("<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" xfId=\"0\"/>");
            sb.Append("</cellXfs>");
            sb.Append("<cellStyles count=\"1\">");
            sb.Append("<cellStyle name=\"Normal\" xfId=\"0\" builtinId=\"0\"/>");
            sb.Append("</cellStyles>");
            sb.Append("<dxfs count=\"0\"/>");
            sb.Append("<tableStyles count=\"0\" defaultTableStyle=\"TableStyleMedium9\"
            defaultPivotStyle=\"PivotStyleLight16\"/>");
            sb.Append("</styleSheet>");
            return sb.ToString();
        }

        private static string getXlWorkbook()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("<workbook xmlns=\"http://schemas.openxmlformats.org/
            spreadsheetml/2006/main\" ");
            sb.Append("xmlns:r=\"http://schemas.openxmlformats.org/
            officeDocument/2006/relationships\">");
            sb.Append("<fileVersion appName=\"xl\" lastEdited=\"4\" lowestEdited=\"4\"
            rupBuild=\"4505\"/>");
            sb.Append("<workbookPr defaultThemeVersion=\"124226\"/>");
            sb.Append("<bookViews>");
            sb.Append("<workbookView xWindow=\"120\" yWindow=\"90\"
            windowWidth=\"23895\" windowHeight=\"14535\"/>");
            sb.Append("</bookViews>");
            sb.Append("<sheets>");
            for (var i = 0; i < nHojas; i++)
            {
                sb.Append("<sheet sheetId=\"");
                sb.Append(i + 1);
                sb.Append("\" r:id=\"rId");
                sb.Append(i + 3);
                sb.Append("\" name=\"");
                sb.Append(sHojas[i]);
                sb.Append("\"/>");
            }
            sb.Append("</sheets>");
            sb.Append("<definedNames>");
            for (var i = 0; i < nHojas; i++)
            {
                sb.Append("<definedName name=\"");
                sb.Append(sHojas[i]);
                sb.Append("\">'");
                sb.Append(sHojas[i]);
                sb.Append("'!$A$1:");
                sb.Append(sRango[i]);
                sb.Append("</definedName>");
            }
            sb.Append("</definedNames>");
            sb.Append("<calcPr calcId=\"125725\" fullCalcOnLoad=\"true\"/>");
            sb.Append("</workbook>");
            return sb.ToString();
        }

        private static string getXlRels()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>");
            sb.Append("<Relationships xmlns=\"http://schemas.openxmlformats.org/
            package/2006/relationships\">");
            sb.Append("<Relationship Id=\"rId1\" ");
            sb.Append("Type=\"http://schemas.openxmlformats.org/
            officeDocument/2006/relationships/styles\" ");
            sb.Append("Target=\"styles.xml\"/>");
            sb.Append("<Relationship Id=\"rId2\" ");
            sb.Append("Type=\"http://schemas.openxmlformats.org/
            officeDocument/2006/relationships/theme\" ");
            sb.Append("Target=\"theme/theme1.xml\"/>");
            for (var i = 0; i < nHojas; i++)
            {
                sb.Append("<Relationship Id=\"rId");
                sb.Append(i + 3);
                sb.Append("\" ");
                sb.Append("Type=\"http://schemas.openxmlformats.org/
                officeDocument/2006/relationships/worksheet\" ");
                sb.Append("Target=\"worksheets/sheet");
                sb.Append(i + 1);
                sb.Append(".xml\"/>");
            }
            sb.Append("</Relationships>");
            return sb.ToString();
        }

        private static string getXlTheme()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>");
            sb.Append("<a:theme xmlns:a=\"http://schemas.openxmlformats.org/
            drawingml/2006/main\" name=\"Office Theme\">");
            sb.Append("<a:themeElements>");
            sb.Append("<a:clrScheme name=\"Office\">");
            sb.Append("<a:dk1><a:sysClr val=\"windowText\" lastClr=\"000000\"/></a:dk1>");
            sb.Append("<a:lt1><a:sysClr val=\"window\" lastClr=\"FFFFFF\"/></a:lt1>");
            sb.Append("<a:dk2><a:srgbClr val=\"1F497D\"/></a:dk2>");
            sb.Append("<a:lt2><a:srgbClr val=\"EEECE1\"/></a:lt2>");
            sb.Append("<a:accent1><a:srgbClr val=\"4F81BD\"/></a:accent1>");
            sb.Append("</a:themeElements>");
            sb.Append("<a:objectDefaults/>");
            sb.Append("<a:extraClrSchemeLst/>");
            sb.Append("</a:theme>");
            return sb.ToString();
        }

        private static string getXlSheet(int nHoja)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("<worksheet xmlns=\"http://schemas.openxmlformats.org/
            spreadsheetml/2006/main\" ");
            sb.Append("xmlns:r=\"http://schemas.openxmlformats.org/          
            officeDocument/2006/relationships\">");
            sb.Append("<dimension ref=\"A1:");
            sb.Append(sRango[nHoja]);
            sb.Append("\"/>");
            sb.Append("<sheetViews>");
            sb.Append("<sheetView tabSelected=\"1\" workbookViewId=\"0\" rightToLeft=\"false\">");
            sb.Append("<selection activeCell=\"A1\" sqref=\"A1\"/>");
            sb.Append("</sheetView>");
            sb.Append("</sheetViews>");
            sb.Append("<sheetFormatPr defaultRowHeight=\"15\"/>");
            sb.Append("<sheetData>");
            if(tipoOrigen.Equals(TipoOrigen.Listas)) sb.Append(getSheetList(nHoja));
            else sb.Append(getSheetTable(nHoja));
            sb.Append("</sheetData>");
            sb.Append("<pageMargins left=\"0.7\" right=\"0.7\" top=\"0.75\"
            bottom=\"0.75\" header=\"0.3\" footer=\"0.3\"/>");
            sb.Append("</worksheet>");
            return sb.ToString();
        }

        private static string getSheetList(int nHoja)
        {
            StringBuilder sb = new StringBuilder();
            var lista = data[nHoja];
            PropertyInfo[] campos = lista[0].GetType().GetProperties();
            sb.Append("<row outlineLevel=\"0\" r=\"1\">");
            string celda;
            string valor;
            string tipo;
            for (int j = 0; j < campos.Length; j++)
            {
                celda = String.Format("{0}1", (char)(65 + j));
                valor = campos[j].Name;
                sb.Append("<c r=\"");
                sb.Append(celda);
                sb.Append("\" s=\"0\" t=\"inlineStr\"><is><t>");
                sb.Append(valor);
                sb.Append("</t></is></c>");
            }
            sb.Append("</row>");
            for (int i = 0; i < lista.Count; i++)
            {
                sb.Append("<row outlineLevel=\"0\" r=\"");
                sb.Append(i + 2);
                sb.Append("\">");
                for (int j = 0; j < campos.Length; j++)
                {
                    celda = String.Format("{0}{1}", (char)(65 + j),i+2);
                    valor = lista[i].GetType().GetProperty(campos[j].Name).
                    GetValue(lista[i], null).ToString();
                    tipo = lista[i].GetType().GetProperty(campos[j].Name).PropertyType.ToString();
                    sb.Append("<c r=\"");
                    sb.Append(celda);
                    sb.Append("\" s=\"0\"");
                    if (tipo.Contains("String"))
                    {                      
                        sb.Append(" t=\"inlineStr\"><is><t>");
                        sb.Append(valor);
                        sb.Append("</t></is>");
                    }
                    else
                    {
                        sb.Append("><v>");
                        sb.Append(valor);
                        sb.Append("</v>");
                    }
                    sb.Append("</c>");
                }
                sb.Append("</row>");
            }          
            return sb.ToString();
        }

        private static string getSheetTable(int nHoja)
        {
            StringBuilder sb = new StringBuilder();
            var tabla = data[nHoja];
            DataColumnCollection campos = tabla.Columns;
            sb.Append("<row outlineLevel=\"0\" r=\"1\">");
            string celda;
            string valor;
            string tipo;
            for (int j = 0; j < campos.Count ; j++)
            {
                celda = String.Format("{0}1", (char)(65 + j));
                valor = campos[j].ColumnName;
                sb.Append("<c r=\"");
                sb.Append(celda);
                sb.Append("\" s=\"0\" t=\"inlineStr\"><is><t>");
                sb.Append(valor);
                sb.Append("</t></is></c>");
            }
            sb.Append("</row>");
            for (int i = 0; i < tabla.Rows.Count; i++)
            {
                sb.Append("<row outlineLevel=\"0\" r=\"");
                sb.Append(i + 2);
                sb.Append("\">");
                for (int j = 0; j < campos.Count; j++)
                {
                    celda = String.Format("{0}{1}", (char)(65 + j), i + 2);
                    valor = tabla.Rows[i][j].ToString();
                    tipo = campos[j].DataType.ToString();
                    sb.Append("<c r=\"");
                    sb.Append(celda);
                    sb.Append("\" s=\"0\"");
                    if (tipo.Contains("String"))
                    {
                        sb.Append(" t=\"inlineStr\"><is><t>");
                        sb.Append(valor);
                        sb.Append("</t></is>");
                    }
                    else
                    {
                        sb.Append("><v>");
                        sb.Append(valor);
                        sb.Append("</v>");
                    }
                    sb.Append("</c>");
                }
                sb.Append("</row>");
            }
            return sb.ToString();
        }
    }
}

7. Explicación Resumida de la Clase Excel

Para cada origen de datos se ha creado un método: "ExportarDeLista" que trabaja con Reflection para extraer los datos de las listas y "ExportarDeTabla" que trabaja con DataTable para extraer los datos de las tablas.

Ambos métodos llaman a una función común y principal llamada "crearDirectoriosArchivos" que primero define las rutas de los directorios y archivos a crear y luego crea los directorios y archivos definidos.

La función "crearDirectoriosArchivos" llama a diferentes funciones una para crear cada archivo XML y para llenar la data de las listas se usa la función "getSheetList" y para llenar la data de las tablas se usa la función "getSheetTable".

Finalmente se comprime los archivos en un solo archivo XLSX y se borra todos los directorios y archivos XML creados temporalmente.

8. Programar el formulario para que use las Clases creadas y Exporte

El último bloque a codificar es el formulario "frmExcel" en el cual debe escribir el siguiente código:

using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.IO;
using System.Diagnostics;
using System.Windows.Forms;

namespace Excel_Crear_XML
{
    public partial class frmExcel : Form
    {
        private beCategoriaProducto obeCatPro;
        private DataSet dstCatPro;
        private string archivoXlsx;
        private string[] hojas;

        public frmExcel()
        {
            InitializeComponent();
        }

        private void llenarDesdeListas(object sender, EventArgs e)
        {
            //Simular que se llenan las listas desde la base de datos
            obeCatPro = new beCategoriaProducto();
            obeCatPro.ListaCategoria = Data.ListaCategorias();          
            obeCatPro.ListaProducto = Data.ListaProductos();
            //Enlazar las listas del objeto principal a las grillas
            dgvCategoria.DataSource = obeCatPro.ListaCategoria;
            dgvProducto.DataSource = obeCatPro.ListaProducto;
            //Habilitar botón de Exportar Listas a Excel y deshabilitar el otro
            btnExportarListas.Enabled = true;
            btnExportarTablas.Enabled = false;
        }

        private void llenarDesdeTablas(object sender, EventArgs e)
        {
            //Simular que se llenan las tablas desde la base de datos
            dstCatPro = new DataSet();
            dstCatPro.Tables.Add(Data.TablaCategorias());
            dstCatPro.Tables.Add(Data.TablaProductos());
            //Enlazar las tablas del DataSet a las grillas
            dgvCategoria.DataSource = dstCatPro.Tables[0];
            dgvProducto.DataSource = dstCatPro.Tables[1];
            //Habilitar botón de Exportar Tablas a Excel y deshabilitar el otro
            btnExportarListas.Enabled = false;
            btnExportarTablas.Enabled = true;
        }

        private void guardarExcel(Action exportar)
        {
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.Title = "Selecciona el Directorio e ingresa Nombre del Archivo Excel";
            sfd.Filter = "Archivos de Excel 2007|*.xlsx";
            if (sfd.ShowDialog().Equals(DialogResult.OK))
            {
                archivoXlsx = sfd.FileName;
                hojas = new string[]{"Categorias", "Productos"};
                Stopwatch oCronometro = new Stopwatch();
                oCronometro.Start();
                exportar();
                oCronometro.Stop();
                MessageBox.Show(String.Format("Archivo Excel fué creado en {0:n0} msg",
                oCronometro.Elapsed.TotalMilliseconds));
            }
        }

        private void exportarDesdeListas()
        {
            Excel.ExportarDeLista(archivoXlsx, hojas, obeCatPro);
        }

        private void exportarDesdeTablas()
        {
            Excel.ExportarDeTabla(archivoXlsx, hojas, dstCatPro);
        }

        private void exportarListasExcel(object sender, EventArgs e)
        {
            guardarExcel(exportarDesdeListas);
        }

        private void exportarTablasExcel(object sender, EventArgs e)
        {
            guardarExcel(exportarDesdeTablas);
        }
    }
}

9. Ejecutar y Probar la Aplicación Windows Forms

Grabar la aplicación y pulsar F5 para ejecutarla, se mostrará una ventana similar a la figura:

Ventana de ejecución del formulario "frmExcel"

Luego clic al primer botón "Llenar desde Listas" y se mostrará en las grillas los datos desde las listas de categorías y productos, tal como se muestra en las siguientes figuras:

Ventana con la Ficha de Categorías para Listas

Ventana con la Ficha de Productos para Listas

Se habilitará el botón de "Exportar Listas a Excel" al cual si se da click se mostrará el siguiente diálogo de guardar:

Diálogo de Guardar Excel para Listas

Escribir el nombre del archivo de Excel 2007, por ejemplo "ListasXML.xlsx" y "Guardar" e inmediatamente se mostrará un cuadro de diálogo con el tiempo que demoró la operación.

Continuando con las pruebas click al botón "Llenar desde Tablas" y se mostrará en las grillas los datos desde las tablas de categorías y productos, similar a las presentadas en las figuras de arriba.

Ventana con la Ficha de Categorías para Tablas

Se habilitará el botón de "Exportar Tablas a Excel" al cual si se da click se mostrará el siguiente diálogo de guardar:

Diálogo de Guardar Excel para Tablas

Escribir el nombre del archivo de Excel 2007, por ejemplo "TablasXML.xlsx" y "Guardar" e inmediatamente se mostrará un cuadro de diálogo con el tiempo que demoró la operación.

Finalmente, pueden abrir los 2 archivos de Excel creados que contendrán ambos 2 hojas: Categorías y Productos con los datos de los orígenes.

10. Comentario Final

Personalmente considero este post como uno de mis favoritos ya que no hay información en Internet sobre cómo crear un archivo de Excel 2007 en forma nativa, es decir creando los archivos XML necesarios para luego comprimirlos en un solo archivo XLSX.

Esta técnica es muy rápida, no necesita de instalar nada, y puede crear archivos de Excel con todo tipo de objetos como gráficos, formas, estilos, formatos, etc. Es la mejor forma para exportar datos sobre todo en la Web ya que también se puede hacer por JavaScript nativo como lo veremos en otro post.

Espero que este post ayude a muchas programadores a entender como es la estructura de un archivo Excel y poder crearlo sin necesidad de usar librerías, ya que según mi opinión solo volviendo a "Crear la Rueda" se puede construir una mejor. Los que usen el refrán "Para que Inventar la Rueda" es porque "NO saben como crearla".

Este Blog nació con ese fin, demostrar que con un poco de ingenio y mucha investigación se puede hacer "cualquier cosa". Finalmente, los quiero dejar con otra reflexión: "Fácil es hacer Complejo lo Simple", pero "Difícil es hacer Simple lo Complejo".

Cuando uno aprende hacer lo Complejo Simple estará en condiciones de resolver cualquier problema en corto tiempo y no esperar a que otro lo haga por ti (Frameworks y Librerías) que éste se hace mas fuerte y tu dependiente de él. Además que te pierdes de lo más interesante.

11. Descarga la Aplicación Windows

2016_08_09_Demo_Excel_Crear_XML