CRUD con LINQ to XML
Como ya sabremos, almacenar datos en formato XML es una práctica bastante habitual por lo que para poder trabajar con esta clase de documentos LINQ ofrece una interfaz con la que se podrán realizar tanto consultas de acción como consultas de selección sobre cualquier fichero de tipo XML. Se trata de LINQ to XML.
En este artículo explicaré cómo usar esta herramienta y para ello realizaré un CRUD sobre un documento XML que guardaré en local en mi aplicación.
- Antes de empezar:
- Crear un proyecto en Visual Studio 2019 de tipo: Web Application ASP .NET Core.
- Usaré Bootstrap para el diseño (opcional)
- También añadir al proyecto el NuGet de Micorosoft.EntityFrameworkCore:
Y ahora, comencemos.
Primero, agregaré a mi aplicación el fichero XML. Esta clase de ficheros estáticos se deben de guardar en la carpeta wwwroot:
- Agregar la carpeta wwwroot al proyecto (este paso no es necesario si se ha creado el proyecto con plantilla MVC) :
- Dentro de esta carpeta agregamos otra que se llame Documents y en esta guardaremos nuestro documento XML:
Para mi ejemplo, mi documento XML se llama: musica.xml. Esta es su estructura:
Para poder acceder a wwwroot y a sus carpetas vamos a crearnos una clase llamada PathProvider. Será un proveedor de rutas que facilitará las rutas de los ficheros que se encuentren dentro de wwwroot. Nos crearemos este fichero en una carpeta a la que llamaremos Helpers:
Una vez creada primeramente debemos de añadir una enumeración que se componga de los nombres de las carpetas de wwwroot con las que queramos trabajar:
Por supuesto, la enumeración se encontrará fuera de la clase pero dentro del namespace de esta.
Como se puede observar, mi enumeración solo consta de un elemento que es la carpeta Documents en la que está almacenado mi fichero XML. Evidemente, si tuviera más carpetas a las que quisiera acceder también debería de añadirlas a mi enumeración.
Además, para trabajar con archivos locales es necesario hacer la inyección de la interfaz IWebHostEnvironment (importar de: Microsoft.AspNetCore.Hosting) la cual permitirá acceder a la carpeta wwwroot:
A continuación, vamos a crear un método que devuelva las rutas de los ficheros. Este método recibirá como parámetros el nombre del fichero y la carpeta desde donde se quiere recuperar el fichero en cuestión:
Analicemos el código. Primeramente, tenemos un String carpeta que será la carpeta a la cual se quiere acceder.
Usando un bucle if apuntando a las carpetas que tenemos en wwwroot y se le asigna a carpeta el nombre de la carpeta a la que se quiere acceder.
Usando el método .Combine (importar de: System.IO) se crea una ruta con el entorno, la carpeta seleccionada y su nombre de fichero indicado. Es importante usar el método .Combine ya que estamos en multiplataforma y este método se adaptará a las distintas maneras que puede haber de escribir una ruta en distintos sistemas operativos.
Por último, se devuelve la ruta completa.
Tener la clase PathProvider es una herramienta de lo más útil ya que es una clase que se crea una vez solo y que se puede usar en múltiples sitios de la aplicación.
A continuación vamos a crearnos dentro de la carpeta Models una clase Album para poder mapear el documento XML.
Teniendo esto vamos a comenzar con los métodos CRUD.
Como buena praxis, crearé una interfaz en donde iré escribiendo los métodos que vaya haciendo. La interfaz se encontrará dentro de una carpeta llamada. Repositories:
Teniendo esto, primero haré los métodos para hacer las consultas de selección. Uno que recuperará todos los elementos del documento y otro que recuperará sólo uno de los elementos.
Nota: recordar hacer la interfaz pública ya que por defecto es privada.
Y ahora, nos creamos el repositorio en sí con la interfaz implementada:
Por el momento dejamos los métodos como están ya que aún necesitamos algunos elementos para poder continuar.
Necesitaremos:
- Hacer uso del objeto XDocument que representará el documento XML.
- Inyectar el PathProvider para obtener la ruta de los ficheros.
- Un String privado en el cual estará la ruta completa al documento.
En el constructor de la clase hacemos la inyección del PathProvider y usando su método MapPath() recuperamos la ruta al documento:
El método de la clase XDocument: .Load() apuntará a un documento XML a partir de la ruta que se le haya especificado como parámetro. En este caso, la ruta viene en la variable path.
- Método GetAlbumes()
Para poder leer un documento XML hay que acceder a sus etiquetas y para ello se usa el método .Descendants(). A este método se le indica el nombre de la etiqueta de la que queramos recuperar sus etiquetas hijas.
En este caso quiero recuperar todas las etiquetas que desciendan de la etiqueta <ALBUM>
Teniendo esto vamos a indicar que por cada etiqueta XML que haya en el documento cree un objeto de la clase Album y los devuelva convertido en lista.
Para hacer esto usaremos los métodos Element() o Attribute() según corresponda.
Cuando hablamos de elementos en XML nos referimos a las etiquetas en sí. Por ejemplo en mi documento tengo las siguientes etiquetas:
<TITULO>, <AUTOR> y <FEHCAPUBLICACION> son etiquetas que se encuentran dentro de otra llamada <ALBUM> y para recuperarlas se usará el método Element()
En cambio, dentro de la etiqueta <ALBUM> tenemos un atributo: ID y para recuperarlo se usará el método Attribute().
Veámoslo con el código:
Importante: a la hora de escribir los nombres de la etiquetas deben de estar igual que en el documento XML ya que LINQ to XML es case sensitive.
- Método GetAlbum()
Este método será parecido al anterior. Recibirá el ID del elemento que se quiera recuperar del documento y devolverá el objeto que coincida con él:
Una vez tengamos estos dos métodos vamos a abrir el fichero Startup y en su método ConfigureServices() resolvemos las dependencias:
Y en su método Configure() le indicamos que vamos a hacer uso de ficheros estáticos para tener acceso a la carpeta wwwroot:
Y por último para poder visualizarlo me voy a crear un controlador en la carpeta Controllers en el cual haré la inyección de la interfaz y llamaré a los métodos del repositorio. También, me crearé las vistas correspondientes usando Scaffolding.
No olvidar en el ActionLink de Details agregarle el parámetro del ID para que lo pueda enviar al método:
Y este sería el resultado:
Ahora, vamos a seguir con las consultas de acción.
- Método para insertar un elemento XML.
Declaramos este método en la interfaz:
Será un método que no devolverá nada pero recibirá los elementos que luego insertaremos dentro del documento XML. En el repositorio implementamos este método.
Para poder insertar habrá que hacer uso de un objeto de la clase XElement. Este objeto representará un elemento del documento XML.
En este caso, xelem representará a la etiqueta <ALBUM>. A este elemento será al que le iremos añadiendo los valores de los elementos y atributos que desciendan de él.
Para añadir el valor de un atributo se tienen dos formas. Una de ellas sería usando XAttribute. Por ejemplo creando un nuevo objeto XAttribute que contenga el nombre del atributo a crear y su valor asignado:
xelem.Add(new XAttribute("ID", id));
O se puede hacer usando el método .SetAttributeValue() y pasarle el nombre del atributo y su valor:
Para añadir nuevos elementos también se debe de usar XElement. La diferencia está en que además de pasarle el nombre de la etiqueta a crear habrá que pasarle el valor que tiene:
Y con el método .Add() se añaden los elementos a su etiqueta padre <ALBUM>
Y por último, el elemento xelem deberá ser añadido también a la etiqueta raíz del documento: <ALBUMES>
El método .Save() recibe la ruta en donde se encuentre nuestro documento y guarda los cambios hechos en él.
Para probarlo simplemente llamamos a este método en el controlador en un método al que llamaré Create así como su correspondiente vista:
- HomeController:
- Vista Create:
Nota: importante que los name de los input coincidan con los parámetros del método HttpPost de Create.
Y este sería el resultado:
Vemos que también se ha añadido en el documento XML:
Por último voy a explicar cómo hacer los métodos de modificar y eliminar. Ambos métodos tienen en común que van a atacar a un elemento XML ya existente y por ello, antes de empezar voy a crear un método privado que localizará este elemento a partir de su ID.
Es un método que devuelve un objeto XElement en concreto para luego poder trabajar con él.
- Método para eliminar un elemento.
Este método sí lo implementaré en la interfaz:
Recibirá el ID del elemento a eliminar.
El primer paso será, usando este ID localizar el elemento en cuestión y para ello usaremos el método GetXElement() creado anteriormente:
Una vez esté localizado, usando el método Remove() que provee la clase XElement lo borramos y guardamos cambios:
Y ahora toca hacer el método en el controlador que llame a este método:
Y en la vista Index, añadimos al enlace Delete el parámetro que luego enviará y que será el ID del elemento a borrar:
Al ejecutar y pulsar en el botón veremos que el elemento se borra del documento.
- Método para modificar.
A diferencia del método de eliminar, no sólo recibirá como parámetro el ID si no que recibirá todas las propiedades para modificar.
Entonces, primero este método irá dentro de la interfaz y luego se implementará en el repositorio:
Como hemos hecho en el anterior método, usando el método GetXElement() localizamos el elemento a editar:
Teniendo el elemento localizado modificamos sus propiedades asignándoles el valor que les llega por parámetros y guardamos los cambios en el documento adecuado con Save()
Finalmente, solo quedaría crearse el método Edit en el controlador y su correspondiente vista.
En el método GET de Edit usando el método GetAlbum() enviaremos el objeto seleccionado al modelo para poder visualizarlo:
Vista:
En la vista Index pasarle el ID al Action Link para enviarlo al método Edit:
Este es el resultado:
Voy a editar el registro de «One Direction«:
Y esto sería todo. Siguiendo estos pasos podremos leer cualquier documento XML así como modificarlo, eliminarlo o insertar nuevos elementos.
Autora: Aurora Moreno López
Curso: Desarrollo Web Full Stack, MultiCloud y Multiplataforma
Centro: Tajamar
Año académico: 2020-2021
Enlace a GitHub: https://github.com/auroraMoreno/LeerDocXML.git