0:00 0 0
XML a DataSet con csharp

XML a DataSet con csharp

  DrUalcman |  febrero 22019

¿Alguna vez haz necesitado importar un XML a una base de datos? ¿O sencillamente te cuesta entender el lenguaje de marcado XML para trabajar con el? ¿Te resulta más fácil manejarte con DataSet DataTable? Hoy tengo la solución ideal para tí.

Hace tiempo tenía una función muy sencilla que me hacía este trabajo, pero tenía un problema, si el documento XML tenía varios niveles, no lo conseguía converir correctamente a un DataSet, y por lo tanto, no era muy eficiente que digamos.

Hoy estaba haciendo una migración de una base de datos, desde Wordpress, a otro sistema que no tenía nada que ver con Wordpress, y por lo tanto necesitaba comprar las tablas y la información. Resulta que Wordpress dispone de una función para la Exportación de datos, bastante sencilla y buena al mismo tiempo. Te extrae TODO el contenido de la base de datos a un archivo XML, o puedes selección sólo algunos datos, como los POST, que es lo que más sule interesar de exportar a otos blogs que no sean Wordpress.

Bien, pues me puse a trabajar con mi función, y ¿adivida que? no funcionaba. Por lo que al final me puse manos a la obra y a crear una función que de verdad me convierta XML en DataSet, pero como siempre, no solo para este caso de Wordpress si no genérica para que la podamos reutilizar más veces. Un día de estos, que era mi intención cuando empecé con este blog, voy a subir mis librería con funciones de este tipo, que seguro que a muchos les podrá arreglar más de un dolor de cabeza.

Leer XML

Primero debemos de agregar los namespace que camos a utilizar

using System.Data;
using System.Data.SqlClient;
using System.Xml;

Luego leemos los datos XML, que en este caso yo los voy a pasar como un string, pero si ya habeis trabajado con XML antes debes de saber de sobra que tambien puedes pasar la ruta de un archivo XML o la dirección URL de una página que devuelva contenido XML.


	    /// 
            /// Convert XML String in DataSet
            ///

            /// Datos en formato XML
            ///
            public static DataSet xml2dataset(string xmlData)
            {
                DataSet ds = new DataSet();
                try
                {
                    XmlDocument xDoc = new XmlDocument();
                    xDoc.LoadXml(xmlData);
                    foreach (XmlNode padre in xDoc)
                    {
                        if (padre.NodeType != XmlNodeType.XmlDeclaration)
                        {
                            XmlNodeList xLista = padre.ChildNodes;
                            GetNodos(xLista, ref ds, padre.Name);
                        }
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                return ds;
            }

Esta función va a requerir de otra a la cual la vamos a sobrecargar para que se repita todas las veces que sea necesaria. A esta función le vamos a pasar por referencia el Objeto DataSet que queremos llenar con los datos del XML. Y para ir identificando las tablas, le pasaremos el nombre del nodo que contendrá los datos. He omitodo el nodo que declara el tipo de XML ya que no hace falta que creemos una tabla con ese. Si es que el los datos XML tiene la declararión de la versión de XML que estamos utilizando, claro.

Ahora la función que va a recorrer los nodos de datos.

	    /// 
            /// Recorer el nodo para extraer los datos
            ///

            /// Nodo XML
            /// Dataset a agregar las tablas
            /// Nombre del nodo para la tabla
            private static void GetNodos(XmlNodeList xLista, ref DataSet ds, string tabla)
            {
                try
                {
                    bool creaPadre = !ds.Tables.Contains(tabla);
                    if (creaPadre) ds.Tables.Add(CreaTabla(xLista, tabla));
                    else ActualizaTabla(ds.Tables[tabla], xLista, tabla);
                    DataTable dt = ds.Tables[tabla];
                    DataRow dr = dt.NewRow();
                    foreach (XmlElement item in xLista)
                    {
                        if (item.NodeType != XmlNodeType.XmlDeclaration)
                        {
                            if (item.ChildNodes.Count > 1)
                            {
                                dr[item.Name] = item.Name + "[" + item.ChildNodes.Count.ToString() + "]";
                                //sobrecarga para comprobar de nuevo el nodo
                                XmlNodeList xLista1 = item.ChildNodes;
                                GetNodos(xLista1, ref ds, item.Name);
                            }
                            else
{
//buscar las propiedades y incluirlas como parte del campo, que es la tabla a enlazar
//para conocer el campo y el valor del mismo dentro de la tabla de este campo, si la hay
if (item.Attributes.Count > 0)
{
string content = dr[item.Name].ToString();
if (!string.IsNullOrEmpty(content)) content += "~";
for (int i = 0; i < item.Attributes.Count; i++)
{
content += item.Attributes[i].Name;
content += ":";
content += item.Attributes[i].InnerText;
content += ";";
}
dr[item.Name] = content;
}
else dr[item.Name] = item.InnerText;
}
                        }
                    }
                    dt.Rows.Add(dr);
                    ds.Tables.Remove(tabla);
                    ds.Tables.Add(dt);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }

Como puedes comprobar es un código bastante sencillo. Pero que a su vez necesita de otras dos pequeñas fuiciones, una que crea la tabla por primera vez, y otra que se encargará de comprobar si la tabla siempre tiene el mismo número de campos.

Esto último es lo que me fallaba en mi primera función, en un XML no todos los nodos tienen que tener el mismo número de elementos, aunque el nodo se llame de la misma manera, es por eso que primero se crea la tabla y luego se comprueba que es igual que el siguiente nodo. Si hay diferencia agrega los nuevos campos y asume que de ahí en adelante siemrpe tendrá esos campos.

Aqui las dos funciones directamente.

	    /// 
/// Crear la tabla con las columnas del nodo XML
///

/// Nodo XML
/// Nombre del nodo para la tabla
///
private static DataTable CreaTabla(XmlNodeList xLista, string tabla)
{
DataTable dt = new DataTable(tabla);
foreach (XmlElement item in xLista)
{
if (!dt.Columns.Contains(item.Name))
{
dt.Columns.Add(new DataColumn(item.Name));
}
}
return dt;
}

///
/// Actualizar las columnas de la tabla con las columnas del nodo XML
///

/// Tabla Original
/// Nodo XML
/// Nombre del nodo para la tabla
///
private static DataTable ActualizaTabla(DataTable Original, XmlNodeList xLista, string tabla)
{
bool actualizar = false;
DataTable dt = new DataTable(tabla);
foreach (XmlElement item in xLista)
{
if (!Original.Columns.Contains(item.Name))
{
actualizar = true;
dt.Columns.Add(new DataColumn(item.Name));
}
}
if (actualizar) Original.Merge(dt, true, MissingSchemaAction.Add);
return Original;
}

Conclusiones

Bueno esto es todo, espero que te sirva de ayuda, como siempre te dejo los enlaces de donde he leído algo de información para ayudarme y refrescarme la memoria, ya que yo no soy muy dado a trabar con XML y por eso, soy de los que prefiero trabajr con DataSet.

Happy coding

#utilidades #CSHARP


0 Comentarios

 
 
 

Archivo