Hoy veremos cómo realizar consultas de acción a archivos XML mediante LINQ. XML (del inglés eXtensible Markup Language, o Lenguaje de Marcas Extensible) es un lenguaje de marcas desarrollado por el consorcio W3C.

Aunque, en un principio, su principal funcionalidad es la de servir de enlace entre distintos tipos de lenguaje y como archivo de configuración, también es utilizado como estándar para el intercambio de información estructurada. Puede ser utilizado en base de datos, editores de texto, hojas de cálculo… etc.

Con “consultas de acción” nos referimos a acciones tipo “CRUD” (Create, Read, Update y Delete, en español Crear, Leer, Actualizar y Borrar) sobre una entidad de datos. En este ejemplo utilizaremos una sencilla colección de películas que podrá ser ampliada (C), consultada (R), modificada (U) y reducida (D) por el propio usuario. La información será almacenada en todo momento en un archivo local llamado “películas.xml”.

Si estamos familiarizados con entidades tipo “LINQ to SQL Classes” o “Ado.net”, nos resultará bastante sencillo. La demostración del tutorial la realizaremos sobre un proyecto MVC.

 

Creación del archivo XML

En primer lugar, tendremos que crear nuestro archivo XML que sirva como base de datos para nuestra aplicación-ejemplo. Puede tener una estructura similar a esta:

<?xml version=”1.0″ encoding=”utf-8″?>
<peliculas>
<pelicula>
<id></id>
<nombre></nombre>
<director></director>
<genero></genero>
<fecha></fecha>
<tagline></tagline>
<img></img>
</pelicula>
</peliculas>

Como vemos, consiste en un contenedor <peliculas> que a su vez almacenará un número “n” de elementos <pelicula>. Estas tiene una serie de elementos hijos a modo de atributos: número de identificación, nombre, director, género, fecha de estreno, tagline o descripción e imagen, que guardará una ruta a una imagen de portada almacenada en internet.

A continuación se muestra un ejemplo de película:

<pelicula>
<id>2</id>
<nombre>Dentro del Laberinto</nombre>
<director>Jim Henson</director>
<genero>Aventura</genero>
<fecha>1986</fecha>
<tagline>Ojalá vineran los goblins y se te llevaran… ahora mismo</tagline>
<img>https://ruta_de_la_imagen_de_portada.jpg</img>
</pelicula>

 

Creación de la aplicación MVC

Haciendo click en “File”, “New” y “Project” seleccionaremos en el siguiente menú “ASP.NET Web Application”. Crearemos una clase “Pelicula” y “ModeloPelicula” dentro de la carpeta “Models”. También añadiremos un controlador “PeliculasController” dentro de la carpeta “Controllers”. Después añadiremos dos vistas, “Index” y “Detalles”, dentro de la ruta “Views/Peliculas”. Por último, mediante el comando “Add Existing item” haciendo click con el botón derecho en el proyecto, añadiremos nuestro archivo “peliculas.xml”.

¡A programar!

Clase “ModeloPelicula”

En primer lugar, crearemos el método constructor que instanciará los datos necesarios para la conexión con el archivo XML:

private XDocument xmldoc;
string rutaxml;public ModeloPelicula()
{
this.rutaxml = HttpContext.Current.Server.MapPath(“~/peliculas.xml”);
this.xmldoc = XDocument.Load(rutaxml);
}

A continuación, implementamos cada uno de los métodos necesarios para leer, crear, modificar y eliminar películas. Estos métodos serán utilizados por la clase controladora “PeliculasController”.

public List GetPeliculas()
{
var consulta = from datos in xmldoc.Descendants(“pelicula”)
select new Pelicula()
{
id = datos.Element(“id”).Value,
nombre = datos.Element(“nombre”).Value,
director = datos.Element(“director”).Value,
genero = datos.Element(“genero”).Value,
fecha = datos.Element(“fecha”).Value,
tagline = datos.Element(“tagline”).Value,
img = datos.Element(“img”).Value
};
if (consulta.Any())
{
return consulta.ToList();
}
return null;
}public Pelicula SelectPelicula(int id)
{
var consulta = from datos in xmldoc.Descendants(“pelicula”)
where datos.Element(“id”).Value == id.ToString()
select new Pelicula()
{
id = datos.Element(“id”).Value,
nombre = datos.Element(“nombre”).Value,
director = datos.Element(“director”).Value,
genero = datos.Element(“genero”).Value,
fecha = datos.Element(“fecha”).Value,
tagline = datos.Element(“tagline”).Value,
img = datos.Element(“img”).Value
};
return consulta.First();
}public void InsertarPelicula(Pelicula p)
{
XElement peli = new XElement(“pelicula”,
new XElement(“id”, p.id),
new XElement(“nombre”, p.nombre),
new XElement(“director”, p.director),
new XElement(“genero”, p.genero),
new XElement(“fecha”, p.fecha),
new XElement(“tagline”, p.tagline),
new XElement(“img”, p.img));
xmldoc.Root.Add(peli);
xmldoc.Save(rutaxml);
}

public void EliminarPelicula(int id)
{
Pelicula p = SelectPelicula(id);
XElement peli = xmldoc.Descendants(“pelicula”).FirstOrDefault(x => x.Element(“nombre”).Value == p.nombre);
if (peli != null)
{
peli.Remove();
xmldoc.Save(rutaxml);
}
}

public void ModificarPelicula(Pelicula p)
{
Pelicula pelivieja = SelectPelicula(int.Parse(p.id));
XElement pelixml = xmldoc.Descendants(“pelicula”).FirstOrDefault(x => x.Element(“nombre”).Value == pelivieja.nombre & x.Element(“id”).Value == pelivieja.id);if (pelixml != null)
{
pelixml.Element(“nombre”).Value = p.nombre;
pelixml.Element(“director”).Value = p.director;
pelixml.Element(“genero”).Value = p.genero;
pelixml.Element(“fecha”).Value = p.fecha;
pelixml.Element(“tagline”).Value = p.tagline;
pelixml.Element(“img”).Value = p.img;string n = pelixml.Element(“nombre”).Value;
string d = pelixml.Element(“director”).Value;
xmldoc.Save(rutaxml);
}
}

Como podemos ver, cada método selecciona entidades de nuestra fuente de datos (en este caso, el archivo XML) utilizando consultas LINQ, de la misma manera que se haría si atacáramos una entidad de base de datos.

Clase Pelicula()

La clase “Pelicula” será utilizada únicamente para “dar forma” a los datos que recojamos del fichero XML y poder empaquetarlos en un tipo de objeto más cómodo de manejar. Solamente hay que declarar sus propiedades.

No importa que los datos sean todos de tipo “string”.

public string id { get; set; }
public string nombre { get; set; }
public string director { get; set; }
public string genero { get; set; }
public string fecha { get; set; }
public string tagline { get; set; }
public string img { get; set; }

Clase PeliculasController()

Como en toda aplicación MVC, la clase controladora es la encargada de gestionar las peticiones de la vista al modelo. Primero, instanciamos un objeto de la clase “ModeloPelicula” directamente en el constructor.

private ModeloPelicula modelo;

public PeliculasController()
{
this.modelo = new ModeloPelicula();
}

Y a continuación, ya podemos implementar los métodos. Las acciones CRUD se realizarán desde dos vistas, “Index” y “Detalles”. Desde el listado “Index” podemos visualizar, crear y eliminar películas. El método “POST” se utiliza para la creación de nuevas películas.

// GET: Peliculas
public ActionResult Index()
{
List<Pelicula> lista = this.modelo.GetPeliculas();
return View(lista);
}// Método para crear películas desde la vista “Index”
// POST: Peliculas
[HttpPost]
public ActionResult Index(string textid, string textnombre, string textdirector, string textgenero, string textfecha, string texttag, string textimg)
{
Pelicula p = new Pelicula
{
id = textid,
nombre = textnombre,
director = textdirector,
genero = textgenero,
fecha = textfecha,
tagline = texttag,
img = textimg
};
this.modelo.InsertarPelicula(p);
List<Pelicula> lista = this.modelo.GetPeliculas();
return View(lista);
}

La vista “Detalles” se utiliza para visualizar los detalles de la película seleccionada. Incluye un formulario (ver “Vista ‘Detalles’“) para modificar la película mediante el método “POST”.

// GET: Peliculas
public ActionResult Detalles(int idpeli)
{
Pelicula peli = this.modelo.SelectPelicula(idpeli);
return View(peli);
}// Método para modificar películas desde la vista “Detalles”
// POST: Peliculas
[HttpPost]
public ActionResult Detalles(string textid, string textnombre, string textdirector, string textgenero, string textfecha, string texttag, string textimg)
{
Pelicula p = new Pelicula
{
id = textid,
nombre = textnombre,
director = textdirector,
genero = textgenero,
fecha = textfecha,
tagline = texttag,
img = textimg
};
this.modelo.ModificarPelicula(p);
Pelicula peli = this.modelo.SelectPelicula(int.Parse(textid));
return View(peli);
}

Por último, tendremos un método “Borrar”. Este método solamente puede ser llamado desde el listado de películas (en “Index”) y realiza una llamada al método “EliminarPelicula()” del modelo y, después, volver a mostrar la página “Index()” actualizada.

public ActionResult Borrar(int idpeli)
{
this.modelo.EliminarPelicula(idpeli);
return RedirectToAction(“Index”);
}

Vista “Index”

Esta vista muestra un listado recogido del archivo XML con todas las películas incluídas. Después del listado, se incluye un formulario en el que se puede introducir un campo id, nombre, director, género, fecha, tagline y una ruta de una imagen de internet para crear una nueva película.

@model List<TutorialLinq.Models.Pelicula>
@{
ViewBag.Title = “Index”;
}<h2>Listado de películas</h2><ul>
@foreach (var peli in Model)
{
<li>@Html.ActionLink(peli.nombre, “Detalles”, “Peliculas”, new { idpeli = peli.id }, null) <a href=”Peliculas/Borrar?idpeli=@peli.id”><span class=”glyphicon glyphicon-remove”></span></a></li>
}
</ul><hr />

<h3>Crear película</h3>

<form method=”post”>
<table>
<tr>
<td>
<label>ID:</label>
</td>
<td>
<input type=”text” name=”textid” />
</td>
</tr>
<tr>
<td>
<label>Título:</label>
</td>
<td>
<input type=”text” name=”textnombre” />
</td>
</tr>
<tr>
<td>
<label>Director:</label>
</td>
<td>
<input type=”text” name=”textdirector” />
</td>
</tr>
<tr>
<td>
<label>Género:</label>
</td>
<td>
<input type=”text” name=”textgenero” />
</td>
</tr>
<tr>
<td>
<label>Fecha:</label>
</td>
<td>
<input type=”text” name=”textfecha” />
</td>
</tr>
<tr>
<td>
<label>Tagline:</label>
</td>
<td>
<input type=”text” name=”texttag” />
</td>
</tr>
<tr>
<td>
<label>Ruta de imagen:</label>
</td>
<td>
<input type=”text” name=”textimg” />
</td>
</tr>
</table>
<div>
<button type=”submit” class=”btn-success”>Crear película</button>
</div>
</form>

Vista “Detalles”

Funciona de manera parecida a “Index”, pero mostrando los detalles de una única película (su fecha de estreno, su imagen de portada, el nombre del director, su género…). También incluye un formulario con los datos de esta película para poder modificarlos. Se incluye, a modo de campo oculto, el número identificador de la película para que la lógica de la aplicación pueda saber qué película se está modificando.

@model TutorialLinq.Models.Pelicula
@{
ViewBag.Title = “Detalles”;
}<h4>#@Model.id</h4>
<h2>@Model.nombre @Model.fecha</h2>
<p><i>”@Model.tagline”</i></p>
<table class=”table-bordered”>
<tr>
<td>
<dl>
<dt>Director</dt>
<dd>@Model.director</dd>
<dt>Género</dt>
<dd>@Model.genero</dd>
</dl>
</td>
<td><img class=”img-responsive” src=”@Model.img” style=”width: 200px;” /></td>
</tr>
</table><hr /><h3>Modificar película</h3>

<form method=”post”>
<table>
<input type=”hidden” name=”textid” value=”@Model.id” />
<tr>
<td>
<label>Título:</label>
</td>
<td>
<input type=”text” name=”textnombre” value=”@Model.nombre” />
</td>
</tr>
<tr>
<td>
<label>Director:</label>
</td>
<td>
<input type=”text” name=”textdirector” value=”@Model.director” />
</td>
</tr>
<tr>
<td>
<label>Género:</label>
</td>
<td>
<input type=”text” name=”textgenero” value=”@Model.genero” />
</td>
</tr>
<tr>
<td>
<label>Fecha:</label>
</td>
<td>
<input type=”text” name=”textfecha” value=”@Model.fecha” />
</td>
</tr>
<tr>
<td>
<label>Tagline:</label>
</td>
<td>
<input type=”text” name=”texttag” value=”@Model.tagline” />
</td>
</tr>
<tr>
<td>
<label>Ruta de imagen:</label>
</td>
<td>
<input type=”text” name=”textimg” value=”@Model.img” />
</td>
</tr>
</table>
<div>
<button type=”submit” class=”btn-info”>Modificar película</button>
</div>
</form>