[C#] ¿Como leer XML con un DataSet?

Iniciado por Siuto, 14 Agosto 2010, 06:16 AM

0 Miembros y 1 Visitante están viendo este tema.

Siuto

Estoy tratando de leer un archivo XML con un DataSet y hasta una parte llegue a ver si alguien me dice el poquito que me falta...

Código (xml) [Seleccionar]
<?xml version="1.0" encoding="utf-8" ?>

<root>

 <persona>
   <id>1</id>
   <nombre>Juan</nombre>
   <apellido>Perez</apellido>
   <hijos>
     <hijo>Juan II</hijo>
     <hijo>Juan III</hijo>
   </hijos>
 </persona>

 <persona>
   <id>2</id>
   <nombre>Carlos</nombre>
   <apellido>Gomez</apellido>
   <hijos>
     <hijo>Carlos II</hijo>
     <hijo>Carlos III</hijo>
   </hijos>
 </persona>

</root>



Código (csharp) [Seleccionar]
using System;
using System.Data;

namespace ConsoleApplication1
{
   class Program
   {
       static void Main(string[] args)
       {
           DataSet ds = new DataSet("root");
           ds.ReadXml("../../XMLFile1.xml");

           foreach (DataRow dr in ds.Tables["persona"].Rows)
           {
               Console.WriteLine("id: " + dr.Field<String>("id"));
               Console.WriteLine("nombre: " + dr.Field<String>("nombre"));
               Console.WriteLine("apellido: " + dr.Field<String>("apellido"));                
               Console.WriteLine();
           }

           Console.ReadLine();
       }
   }
}



Este codigo anda perfecto, lo que no se es como hacer para leer la lista de hijos de cada persona (no necesariamente son dos hijos por persona).

[D4N93R]

Hola,

Pues, al igual que DataSet toma los Child Nodes del nodo Persona como Rows, (  foreach (DataRow dr in ds.Tables["persona"].Rows)) puedes hacer lo mismo dentro de ese, pero desde el dataset sacas la tabla Hijos. Si revisas el DataSet, lo más seguro es que tengas 3 tablas, persona, hijos, e hijo.

Persona, es la lista de personas.

Hijo es la lista de Hijos,

Hijos es un registro conector, es decir, una tabla intermedia de una relación Muchos-Muchos, en dónde estará el Id de Persona Y el Id de hijo.

Por ejemplo,si en HIJOS hay un registro asi: 2,5 significa que en la tablas HIJO el ID 5 pertenece a la persona ID 2

Todo eso lo crea automático el DataSet, y puedes hacer selects de eso algo así:

Código (csharp) [Seleccionar]
ds.Tables["hijo"].Select("hijos_Id = 1")

Saludos!




Siuto

#2
Gracias por la respuesta me acerco un poco mas, pero lo resolví de otra formar. Dejo como lo hice por si alguien le sirve...

De todas formas si hay una forma mas óptima y alguien quiere postearla es bienvenida.

Código (csharp) [Seleccionar]
using System;
using System.Data;
using System.Linq;

namespace ConsoleApplication1
{
   class Program
   {
       static void Main(string[] args)
       {
           DataSet ds = new DataSet("root");
           ds.ReadXml("../../XMLFile1.xml");


           foreach (DataRow drp in ds.Tables["persona"].Rows)
           {
               // Esta columna de la tabla la genera el DataSet no el archivo XML
               Int32 persona_Id = drp.Field<Int32>("persona_Id");

               Console.WriteLine("persona_Id: " + persona_Id);
               Console.WriteLine("id: " + drp.Field<String>("id"));
               Console.WriteLine("nombre: " + drp.Field<String>("nombre"));
               Console.WriteLine("apellido: " + drp.Field<String>("apellido"));


               var query = from p in ds.Tables["persona"].AsEnumerable()
                           join hs in ds.Tables["hijos"].AsEnumerable() on p.Field<Int32>("persona_Id") equals hs.Field<Int32>("persona_Id")
                           join h in ds.Tables["hijo"].AsEnumerable() on hs.Field<Int32>("hijos_Id") equals h.Field<Int32>("hijos_Id")
                           where p.Field<Int32>("persona_Id") == persona_Id
                           select h;

               foreach (DataRow drh in query)
               {
                   Console.WriteLine("Hijo: " + drh.Field<String>("hijo_Text"));
               }
               
               Console.WriteLine();
           }

           Console.ReadLine();
       }
   }
}

[D4N93R]

Que bien!

Bueno te digo, es prácticamente lo mismo que te dije, pero usando LINQ. Como optimización (más bien reducción de código, puedes mejorar esa consulta de modo tal de que elimines el primer foreach. Pero así está muy bien y bien claro.

Te hice este demo para que veas la continuación de lo que yo creo debería ser tu Query:
Código (csharp) [Seleccionar]

static void Main(string[] args)
{
   DataSet ds = new DataSet("root");
   ds.ReadXml("../../XMLFile1.xml");

   var resultNested = from persona in ds.Tables["persona"].AsEnumerable()
                       select new
                       {
                           Nombre = persona.Field<string>("nombre"),
                           Apellido = persona.Field<string>("apellido"),
                           ID = persona.Field<Int32>("persona_Id"),
                           Hijos = from hijos in ds.Tables["hijos"].AsEnumerable()
                                   join hijo in ds.Tables["hijo"].AsEnumerable() on hijos.Field<Int32>("hijos_Id") equals hijo.Field<Int32>("hijos_Id")
                                   where hijos.Field<Int32>("persona_Id") == persona.Field<Int32>("persona_Id")
                                   select new { Nombre = hijo.Field<string>("hijo_Text") }
                       };

   foreach (var p in resultNested)
   {
       Console.WriteLine(p.Nombre+" "+ p.Apellido);
       foreach (var h in p.Hijos)
       {
           Console.WriteLine(" -"+h.Nombre);
       }
   }

   Console.ReadLine();
}


Como puedes ver, creo typos anónimos on-the-fly, y con una propiadad que es una colección como resultado de otro query. LINQ es poderoso, más que todo en reducción de código, y hace que se vea mucho más simple, aunque en temas de rendimiento, es prácticamente igual.

Un saludo!

EDIT: Se me olvidó decirte xD, de esta forma también estás separando el controller del view, por así decirlo.!