lunes, 23 de junio de 2014

Pregunta C# (2 de 20): ¿Cómo Parsear un Archivo XML?

Tabla de Contenido

0. Introducción
1. ¿Qué es XML?
2. Creación de un Lector de XML: XmlReader
3. Validación de Datos en un Archivo XML
3.1 Validación con un DTD
3.2 Validación con XSD
4. Conformidad de Datos
5. Exploración de Nodos de un Documento XML
6. Lectura de Elementos
7. Lectura de Atributos
8. Conversión a Tipos CLR
9. Programación Asincrónica
10. Consideraciones de Seguridad
11. Ejemplo con Aplicación Consola (RESPUESTA)
12. Conclusiones
13. Glosario
14. Literatura & Enlaces

0. Introducción

Grandiosa oportunidad para responder otra de las preguntas comunes sobre uso del lenguaje de programación C#. Esta vez nos centraremos en explorar la clase XmlReader, la cual nos va a permitir leer un archivo XML como fuente de datos para nuestras aplicaciones y poder ejecutar tareas como: desplazamiento entre los nodos, leer el contenido y los atributos de cada nodo. A pesar de que la pregunta original resulta breve (incluiré la respuesta al final del documento) me extenderé con varias secciones interesantes relacionadas con esta tarea de parsing de archivos XML: Validación y conformidad de datos, conversión a tipos CLR, programación asincrónica, y la descripción de varias consideraciones de seguridad. Al final, mostraré un ejemplo completo, y además, la respuesta dada en la Microsoft Virtual Academy.

1. ¿Qué es XML?

XML es un formato de archivo de texto para la estructuración de datos legible tanto para humanos como para máquinas. Se considera un lenguaje de marcado. Las marcas consisten en secciones de datos con atributos que describen propiedades cualitativas y cuantitativas. Las secciones de datos son encerradas por nodos. Cada nodo puede contener cero o más nodos anidados según sea necesario para la estructuración de la información que queremos representar, transmitir, visualizar, &c.

Un ejemplo sencillo de un archivo de texto XML, podría ser:

Archivo XML libros.xml:
La primera línea representa un encabezado que establece la versión de conformidad de XML con estándares. Notemos en las líneas 2-24 el nodo biblioteca, este nodo posee hasta tres nodos anidados de tipo libro, al mismo tiempo este último nodo contiene nodos descriptivos de una obra literaria:
  • titulo
  • autor
Este último contiene otros dos nodos para especificidades granulares del nombre de un escritor (nombre, y apellido).


Como nos puede resultar evidente, la lectura de este tipo de archivos es relativamente cómoda para nosotros los humanos. Las máquinas o sistemas de cómputo también se benefician de este tipo de archivos de texto gracias a su estructura en forma de árbol:
Estructura árbol de un archivo XML
Figura 1. Estructura árbol de un archivo XML.

A continuación trataremos varios temas relacionados de lectura, recorrido, validación, conformidad, entre otras operaciones más, sobre de archivos XML.

2. Creación de un Lector XML: XmlReader

La biblioteca base de clases de .NET Framework está compuesta por un nombre de espacio especializado en el manejo de documentos XML: System.Xml [3]. Este nombre de espacio contiene la clase XmlReader [4] para el acceso a datos XML desde diferentes fuente (e.g., archivo en unidad de almacenamiento local, en una red, o en memoria).


Para crear una instancia de este lector de XML, usamos el método Create [5] (este método implementa el patrón de diseño factoría [factory]), el cual posee la siguiente lista sobrecargada:
Lista sobrecargada método XmlReader.Create
Figura 2. Lista sobrecargada método XmlReader.Create [5].
Para poner como caso de creación de una instancia de este tipo de lector, usemos la versión de Create de la siguiente firma [6]:

public static XmlReader Create(string inputUri)

Descripción puntual:
  • Parámetros:
    • string inputUri: cadena de texto que representa la ubicación URI en donde se haya el archivo XML.
  • Tipo de retorno: instancia de XmlReader.
Su uso consistente básicamente en:

// Creación de un objeto XmlReader:
XmlReader lectorXml = XmlReader.Create ("libros.xml");

[Nota: Para conocer las demás versiones sobrecargadas recomiendo la visita al enlace en [5]. En las secciones siguientes exploraremos otras firmas de Create.]

3. Validación de Datos en un Archivo XML

La estructura de una archivo puede ser validada (i.e., validación de la relación entre elementos, tipos de datos permitidos, y restricciones de contenido en el documento) de dos formas distintas: a través de un DTD (Document Type Definition, ~documento de definición de tipos) o través de un lenguaje de definición de esquema (formalmente XML Schema Definition Language). Estos dos enfoques de validación permiten crear documentos XML bien formados, además de que estos últimos posean los requerimientos sintácticos definidos por el W3C lo que los hace más serios para la estructuración de datos.

Empecemos por explorar el primero de estos dos.

3.1 Validación con un DTD

Podemos definir un conjunto de restricciones, reglas, y definiciones sobre las relaciones permitidas entre los elementos integrales de un documento XML, además de los tipos de datos permitidos para los elementos, y restricciones sobre el contenido almacenar en el documento por medio de un documento de definición de tipos (DTD, document type definition). Este tipo de validación está sujeta a las recomendaciones del W3C [7] y puede ser utilizado sobre un objeto XmlReader para la validación de la formación o confección de un archivo XML.

En [8] encontramos que:
DTDs use a formal grammar to describe the structure and syntax of complaint XML documents; they specify the content and values allowed for the XML document.
Como demostración de este enfoque de validación crearemos un documento XML con la definición de tipos, restricciones, y relaciones; y enseguida escribiremos código fuente en C# para leer este archivo con XmlReader y especificar el tipo de validación sobre el documento XML con DTD:

Notemos cómo hemos incluido un nuevo nodo que no se haya definido en la sección validación (líneas 3-8) en la línea 17: marca. Además, hemos omitido el atributo obligatorio tipo para el elemento producto en la instancia de la línea 19. Ahora con un objeto XmlReader validemos en lo que hemos detectado a ojo desnudo:

Archivo de código fuente ValidacionConDTD.cs [enlace alternativo]:
En la línea 14 creamos un objeto XmlReaderSettings [9] que nos sirve para especificar la configuración de validación para el objeto XmlReader. Más adelante, sobre la línea 24 creamos el objeto XmlReader pasando como argumentos el nombre del documento XML que queremos validar, y la configuración de la validación:


XmlReader lectorXml = XmlReader.Create ("almacen.xml", configXml);

En el ciclo while (línea 27) iteramos sobre el contenido del archivo XML almacen.xml.

Compilación:


  1. csc /target:exe ValidacionConDTD.cs

Ejecución assembly:


  1. .\ValidacionConDTD.exe

Resultado:
Ejecución assembly ValidacionConDTD.exe
Ejecución assembly ValidacionConDTD.exe.

3.2 Validación con XSD

Un esquema XSD describe la estructura de un documento XML [10], por lo tanto se trata de otro de los métodos o esquemas de validación disponibles para objetos XmlReader. Aprendamos de uso con este ejemplo introductorio:

Archivo XSD esquemaLibros.xsd [enlace alternativo]:

Archivo XML libros2.xml [enlace alternativo]:

Archivo de código fuente ValidacionConXSD.cs [enlace alternativo]:

En la línea 13 creamos un objeto de representación del esquema definido en el archivo esquemaLibros.xsd. En las líneas 20-23 creamos la configuración del tipo de enfoque a utilizar para realizar la validación. Nos resta crear el objeto XmlReader (línea 26) y empezar el proceso de parsing (línea 29).

Compilación:


  1. csc /target:exe ValidacionConXSD.cs

Ejecución assembly:


  1. .\ValidacionConXSD.exe

Resultado:
Ejecución assembly ValidacionConXSD.exe
Figura 4. Ejecución assembly ValidacionConXSD.exe.

4. Conformidad de Datos

En la clase XmlReaderSettings están definidas las propiedades para establecer el grado de conformidad de caracteres y validación de los elementos de acuerdo a un esquema de definición (e.g., validación de nombres de nombres de elementos: no está permitido el inicio de nombre con un número).


Precisamente, los métodos que permiten establecer el grado de conformidad en la configuración (instancia de XmlReaderSettings) de un objeto XmlReader son:
  • XmlReaderSettings.CheckCharacters [12]
  • XmlReaderSettings.ConformanceLevel [13]
Ejemplos de uso:

XmlReaderSettings configXml = new XmlReaderSettings();

// Establecimiento del grado de confomidad en el documento XML:
configXml.ConformanceLevel = ConformanceLevel.Fragment;

XmlReader lectorXml = XmlReader.Create ("archivo.xml", configXml);

[Nota: Seguramente en artículos futuros entraremos en detalles específicos sobre el manejo de este de conformidad con fuentes de datos XML.]

5. Exploración de Nodos de un Documento XML


La clase XmlReader posee varios métodos para la navegación (lectura, pasar al siguiente nodo, desplazamiento al contenido, lectura de subnodos). En la Figura 5 se describen con más detalle cada una de estas operaciones:
Métodos de navegación de documento XML con XmlReader
Figura 5. Métodos de navegación de documento XML con XmlReader [4].
Archivo XML libros.xml [enlace alternativo]:
Archivo C# ExploracionNodos.cs [enlace alternativo]:

En la la línea 11 creamos una instancia de XmlReader y le pasamos como argumento el archivo XML que queremos explorar. En la línea 15 usamos el método MoveToContent [19] para desplazarnos a la sección de nodos de contenido. Con el ciclo while (líneas 17-24) recorremos el documento XML nodo a nodo. En la línea 20 a través de la sentencia de selección if validamos que el nodo actual se trata de un nodo de contenido (con la propiedad Value obtenemos el valor y los mostramos en la salida estándar).

Compilación:


  1. csc /target:exe ExploracionNodos.cs

Ejecución assembly:


  1. .\ExploracionNodos.exe

Resultado:
Ejecución assembly ExploracionNodos.exe
Figura 6. Compilación y ejecución assembly ExploracionNodos.exe.

6. Lectura de Elementos XML


La clase XmlReader también posee métodos y propiedades para para el procesamiento de elementos, es decir, su lectura. En la Figura 7 [4] se enumeran varios de los métodos disponibles en XmlReader para la tarea en cuestión:
Lista métodos de lectura de elementos en XmlReader
Figura 7. Lista métodos de lectura de elementos en XmlReader.
Ejemplo de uso:

[Nota: Para este ejemplo reutilizamos el archivo XML libros.xml de la sección anterior.]

En la la línea 11 creamos una instancia de XmlReader y le pasamos como argumento el archivo XML que queremos explorar. Con el ciclo while (líneas 13-35) atravesamos el archivo XML libros.xml nodo a nodo. Este código imprime las marcas (nodos) que son parte del archivo (e.g., libro, titulo, autor, nombre, apellido).

Compilación:


  1. csc /target:exe LecturaElementosXML.cs

Ejecución assembly:


  1. .\LecturaElementosXML.exe

7. Lectura de Atributos XML

Los elementos o nodos pueden estar compuestos por uno o más atributos. Los métodos de XmlReader permiten procesar estos atributos. Exampli gratia, el método MoveToAttribute permite recorrer el conjunto de atributos pertenecientes al nodo actual donde se haya el lector. En la Figura 8 [4] se resumen varios de estos métodos.
Lista métodos de lectura de atributos en XmlReader
Figura 8. Lista métodos de lectura de atributos en XmlReader [4].

Ejemplo de uso:

Archivo XML almacen2.xml [enlace alternativo]:

Archivo C# LecturaAtributosXML.cs [enlace alternativo]:

En la la línea 11 creamos una instancia de XmlReader y le pasamos como argumento el archivo XML que queremos explorar. Con el ciclo while (líneas 13-28) recorremos los nodos del archivo almacen2.xml. Con la expresión lectorXml.HasAttributes validamos que el nodo actual posea atributos. El resto de código (líneas 18-23) se encarga de mostrar uno a uno los atributos del nodo actual donde está posicionado lectorXml. Con la expresión de la línea 27 

lectorXml.MoveToElement();


Desplazamos al lector a la última posición antes de leer los atributos. Esto va a permitir continuar con el siguiente nodo y explorar sus atributos (si los tiene).

Compilacion:


  1. .\LecturaAtributosXML.cs

Ejecución assembly:


  1. csc /target:exe LecturaAtributosXML.cs

Resultado:
Ejecución assembly LecturaAtributos.exe
Figura 9. Ejecución assembly LecturaAtributos.exe.

8. Conversión a Tipos de la CLR

Otra de las facultadas de la clase XmlReader es la de convertir los valores leídos de un archivo XML y convertirlos a tipos de la CLR, en lugar de simples cadenas de caracteres (string).

Por otro lado, como advierten en [4], el hecho de convertir a tipos de la CLR directamente nos exonera de la tarea manual de conversión. Y estos se logra a través de dos tipos de métodos:
  • ReadElementContentAsXXX: donde -XXX- corresponde con un tipo de dato específico (e.g.Boolean, DateTime, Int32, Int64, String). Estos métodos sólo se pueden invocar en nodos.
  • ReadContentAsXXX: donde -XXX- corresponde con un tipo de dato específico (e.g.BooleanDateTimeInt32Int64String). Estos métodos leen el contenido textual de la posición actual del lector.
[Nota: Más información acerca de estos métodos en [4].]

Ejemplo de uso:

Compilación


  1. csc /target:exe ConversionATiposCLR.cs

Ejecución assembly:


  1. .\ConversionATiposCLR.exe

Resultado:
Ejecución assembly ConversionATiposCLR.exe
Figura 10. Ejecución assembly ConversionATiposCLR.exe.

9. Programación Asincrónica

Desde [4] nos informan que la mayoría de los métodos sincrónicos de XMLReader tienen su contraparte asincrónica. Los métodos asincrónicos son los que poseen el postfijo Async en su nombre.


[Nota: Para saber más acerca de programación asincrónica recomiendo la lectura del artículo Expresiones Lambda en C# - Parte 4: Expresiones Lambda y Asincronismo.]

10. Consideraciones de Seguridad

Algunas de las consideraciones de seguridad encontradas en [4]:
  • La lectura de archivos XML es proclive a generar excepciones, por eso es recomendable el tratamiento apropiado de estas para mantener en funcionamiento de la aplicación.
  • El uso del método de validación basado en DTD es propenso a fallas de denegación de servicio, y sobretodo cuando se trata con fuentes de datos de poca confianza.
  • Asegúrese que las fuentes externas de XML mantenga un grado moderado de confianza y seguridad.
  • La lectura de un archivo XML puede tardar bastante tiempo, sobretodo con archivos grandes. Se recomienda:
    • Limitar el tamaño del documento.
  • Los objetos XmlReaderSettings pueden contener información sensible (e.g., credenciales de usuario, por eso tenga cuidado la exposición de datos confidenciales.

11. Ejemplo con Aplicación Consola

Este ejemplo es presentado en el curso Twenty C# Questions Explained de la Microsoft Virtual Academy que actualmente (2014-06-23) estoy cursando.

En la línea 12 creamos una cadena de caracteres para representar un documento XML en memoria de trabajo. Pasamos esta cadena de caracteres como argumento al método ParsingArchivoXml en la línea 22. Dentro del método ParsingArchivoXml ocurre varias cosas interesantes:
  • Línea 28: Creación de objeto StringBuilder [15] para concatenar los resultados de las operaciones del lector de XML.
  • Línea 32: creación del objeto XmlReader a partir de un objeto StringReader [16], el cual contiene la representación del documento XML a analizar (parsing).
  • Línea 34: desplazamiento al elemento libro con el método ReadToFollowing [17].
  • Línea 35: desplazamiento al primer atributo del elemento actual con el método MoveToFirstAttribute [18].
  • Línea 37: obtenemos el valor actual del atributo.
  • Línea 39: concatenación del valor anterior al objeto StringBuilder.
  • Línea 41: desplazamiento al siguiente elemento: titulo.
  • Línea 43: concatenación del valor del elemento titulo.
  • Línea 46: impresión de la operación de concatenación con el objeto StringBuilder.
Compilación:


  1. csc /target:exe ParseArchivoXml.cs

Ejecución assembly:


  1. .\ParsegArchivoXml.cs

Resultado:
Ejecución assembly ParseArchivoXml.exe
Figura 11. Ejecución assembly ParseArchivoXml.exe.

12. Conclusiones

El estudio de la respuesta a la pregunta ¿Cómo Hacer un Parsing de Archivos XML? ha representando una gran oportunidad para conocer las bondades y potencialidades del dominio de la operación de parsing (~análisis) sobre archivos o documentos XML. La validación sobre este tipo de documentos también es otro objetivo de dominio para crear aplicaciones robustas cuando de tratar y procesar archivos documentos XML se trata. Los ejemplos presentados demostraron el conocimiento de los conceptos esenciales o referencia básica sobre la operación de parsing sobre documentos XML.

13. Glosario

  • CLR
  • Compilación
  • Conversión
  • DTD
  • Esquema
  • Parse
  • Parsing
  • Validación
  • XML
  • XSD

14. Literatura & Enlaces

[1]: Microsoft Virtual Academy (MVA) - http://www.microsoftvirtualacademy.com
[2]: XML - Wikipedia, the free encyclopedia - http://en.wikipedia.org/wiki/XML
[3]: System.Xml Namespace () - http://msdn.microsoft.com/en-us/library/system.xml(v=vs.110).aspx
[4]: XmlReader Class (System.Xml) - http://msdn.microsoft.com/en-us/library/system.xml.xmlreader(v=vs.110).aspx
[5]: XmlReader.Create Method (String) (System.Xml) - http://msdn.microsoft.com/en-us/library/w8k674bf(v=vs.110).aspx
[6]: Extensible Markup Language (XML) 1.0 (Fourth Edition) - http://www.w3.org/TR/2006/REC-xml-20060816/
[7]: World Wide Web Consortium (W3C) - http://www.w3.org/
[8]: Validation Using a DTD with XmlReader - http://msdn.microsoft.com/en-us/library/vstudio/z2adhb2f(v=vs.100).aspx
[9]: XmlReaderSettings Class (System.Xml) - http://msdn.microsoft.com/en-us/library/system.xml.xmlreadersettings(v=vs.110).aspx
[10]: XML Schema Tutorial - http://www.w3schools.com/Schema/default.asp
[11]: XML Schema (W3C) - Wikipedia, the free encyclopedia - http://en.wikipedia.org/wiki/XSD
[12]: XmlReaderSettings.CheckCharacters Property (System.Xml) - http://msdn.microsoft.com/en-us/library/system.xml.xmlreadersettings.checkcharacters(v=vs.110).aspx
[13]: XmlReaderSettings.ConformanceLevel Property (System.Xml) - http://msdn.microsoft.com/en-us/library/system.xml.xmlreadersettings.conformancelevel(v=vs.110).aspx
[14]: XmlReader.Read Method (System.Xml) - http://msdn.microsoft.com/en-us/library/system.xml.xmlreader.read(v=vs.110).aspx
[15]: StringBuilder Class (System.Text) - http://msdn.microsoft.com/en-us/library/system.text.stringbuilder(v=vs.110).aspx
[16]: StringReader Class (System.IO) - http://msdn.microsoft.com/en-us/library/system.io.stringreader(v=vs.110).aspx
[17]: XmlReader.ReadToFollowing Method (String) (System.Xml) - http://msdn.microsoft.com/en-us/library/ms162536(v=vs.110).aspx
[18]: XmlReader.MoveToFirstAttribute Method (System.Xml) - http://msdn.microsoft.com/en-us/library/system.xml.xmlreader.movetofirstattribute(v=vs.110).aspx
[19]: XmlReader.MoveToContent Method (System.Xml) - http://msdn.microsoft.com/en-us/library/system.xml.xmlreader.movetocontent(v=vs.110).aspx


J

No hay comentarios:

Publicar un comentario

Envíe sus comentarios, dudas, sugerencias, críticas. Gracias.