XQuery
[Consultas sobre documentos XML]

Fecha: 27/Oct/2004 (27 de Octubre de 2004)
Autor: Luis Ruiz Pavón [luis_ruiz_pavon@hotmail.com]

 


Introducción.

Hace relativamente poco tiempo que utilizo XML para mis aplicaciones. Hace 2 meses me pidieron desarrollar una aplicación Web de consulta sin que se apoyase en una BB.DD y la verdad es que me quedé bloqueado.
No se pretendía almacenar un histórico de información, sino que se quería consultar cierta información de unos ficheros planos que se generaban día a día.
Entonces fue cuando me hablaron de XQuery y, la verdad que esto simplificó todo el desarrollo de la aplicación.
La solución fue crear en tiempo de ejecución un fichero XML con el contenido de los ficheros y realizar una consulta XQuery en base a unos parámetros de selección. Esta consulta devolvía un fichero XML con los resultados tratados con una hoja de estilos XSLT.

¿Qué es XQuery?

Es un lenguaje de consulta estándar publicado por el W3C (World Wide Web Consortium)diseñado para procesar datos XML y basesde datos cuya estructura es similar a la de un documento XML.

Una breve introducción.

La capacidad y flexibilidad de XQuery y el uso intensivo que hace de XPath (Es un lenguaje para recuperar nodos y elementos de un documento XML) lo convierten en el lenguaje de consulta respaldado por el W3C para usarse sobre entornos y documentos XML.

En el siguiente recuadro (figura 1) podemos observar algunas de las especificaciones del W3C. Como podemos observar la especificación 1.0 de XPath perteneció a XSL 1.0 y luego se desarrollo como una especificación separada. Actualmente XPath 2.0 se está desarrollando paralelamente junto con la especificación 1.0 de XQuery.

Figura 1 

Las especificaciones que se encuentran detrás de la línea discontinua se encuentran liberadas, mientras que las otras se está trabajando en ellas "Work in Progress”. Se puede ver su estado actual en la página http://www.w3.org.

El futuro de XQuery.

Será el lenguaje de consulta universal para trabajar con el entorno de XML y abrirá nuevas posibilidades para consultar almacenes de datos:

Creación del proyecto.

Una vez realizada una pequeña introducción sobre XQuery vamos a pasar a desarrollar nuestro pequeño proyecto, con el podremos ejecutar consultas sobre un documento Xml y mostrar los resultados en otro fichero Xml.

El primer paso será crearnos un proyecto nuevo C# en Visual Studio .NET (File à New à Project)

Figura 2

Y pulsamos OK.

Ya tenemos nuestro proyecto creado. Ahora el siguiente paso es cargar la referencia a nuestra DLL (Microsoft.Xml.XQuery.dll)

Figura 3

Para ello, en la ventana Solution Explorer (Figura 4), pinchamos con el botón derecho del ratón sobre References, y nos aparecerá un menú flotante. Pinchamos sobre Add Reference… :

Figura 4

Nos aparecerá la siguiente ventana (Figura 5), pinchamos sobre el botón Browse, para seleccionar la ubicación de la DLL.

Figura 5

Una vez que hayamos seleccionado la DLL, en la lista Selected Components, aparecerá nuestra DLL (Figura 6)

Figura 6

Pulsamos sobre OK, y se añadirá a nuestras referencias:

Figura 7

No situamos en la cabecera de la clase Class1.cs de nuestro proyecto, e importamos el paquete Microsoft.Xml.XQuery utilizando la cláusula using:


using System;
using Microsoft.Xml.XQuery;

namespace execQuery

A continuación vamos a pasar codificar nuestra aplicación.

Lo primero será pedir por pantalla el nombre del fichero Xml que vamos a procesar y el fichero que contiene la query:

class Class1
{
	[STAThread]
	static void Main(string[] args)
	{
		try
		{
			Console.WriteLine("Control de ejecución de consultas XQuery ");
			Console.WriteLine("---------------------------------------- ");
			Console.WriteLine("");
			Console.Write("Fichero Xml: ");
			string fileName = Console.ReadLine();
			string alias =  "aliasXml";  
			Console.Write("Fichero Query: ");     
			string query = Console.ReadLine();

Como podéis observar, hemos declarado un campo de tipo string llamado alias, que hace referencia al fichero Xml en la query.

A continuación creamos la colección XQueryNavigatorCollection, que contendrá los ficheros Xml con sus respectivos alias. En nuestro caso añadimos el fichero Xml y su alias.

/* Creamos la colección */
XQueryNavigatorCollection xqNav = new XQueryNavigatorCollection();  
                      
/* Añadimos el archivo Xml a la colección.
	* El fichero Xml será referenciado en la query por el alias
	*/ 
xqNav.AddNavigator(fileName, alias ); 

El siguiente paso es leer el contenido del fichero que contiene la query que queremos procesar, para ello es necesario importar el paquete System.IO:

using System;
using Microsoft.Xml.XQuery;
using System.IO;

namespace execQuery

Una vez importado ya podemos hacer referencia a la clase StreamReader, que se utiliza para leer el contenido de un fichero.

     /* Copiamos el contenido del fichero de la Query
      * en una variable interna
      */
     string sQuery = String.Empty;

     /* Creamos el flujo */
     StreamReader sr = new StreamReader(query);
     /* Leemos el contenido y lo almacenamos */
     sQuery = sr.ReadToEnd();
     /* Cerramos el flujo */
     sr.Close();

El siguiente paso será compilar la query que acabamos de leer para ver si su sintaxis es correcta. Para ello creamos un objeto de la clase XQueryExpression, pasándole como parámetro la variable que almacena el contenido del fichero de la Query:

/* Compilamos la Query */
XQueryExpression expr = new XQueryExpression(sQuery);

Por último, ejecutamos la query y mostramos lo resultados en un fichero Xml. Debemos importar otro paquete (System.Diagnostics) para poder abrir el fichero Xml con los resultados:

using System;
using Microsoft.Xml.XQuery;
using System.IO;
using System.Diagnostics;				

/* Ejecutamos la query y mostramos los resultados */
	Console.WriteLine("Ejecutando consulta XQuery...");
	StreamWriter sw = new StreamWriter("resultados.xml",false,System.Text.Encoding.UTF8);
	sw.WriteLine("<?xml version='1.0'?>" + (expr.Execute(xqNav)).ToXml());
	sw.Close();
	/* Abrimos el fichero con los resultados */
	Process.Start("explorer.exe", "resultados.xml");
	}
	catch (Exception ex)
	{
		Console.WriteLine("Se ha producido un error: " + ex.Message);
		Console.Read();
	}
}
}
}

Con esto nuestro programa quedaría finalizado, aunque si queremos atrapar las posibles excepciones que se puedan producir y no termine de manera anormal nuestro programa, recomiendo englobar todas las instrucciones dentro de un try catch. A continuación se muestra el código completo del programa:


using System;
using Microsoft.Xml.XQuery;
using System.IO;
using System.Diagnostics;

namespace execQuery
{

	class Class1
	{
		[STAThread]
		static void Main(string[] args)
		{
			try
			{
				Console.WriteLine("Control de ejecución de consultas XQuery ");
				Console.WriteLine("---------------------------------------- ");
				Console.WriteLine("");
				Console.Write("Fichero Xml: ");
				string fileName = Console.ReadLine();
				string alias =  "aliasXml";  
				Console.Write("Fichero Query: ");     
				string query = Console.ReadLine();
    
				/* Creamos la colección */
				XQueryNavigatorCollection xqNav = new XQueryNavigatorCollection();  
                      
				/* Añadimos el archivo Xml a la colección.
				 * El fichero Xml será referenciado en la query por el alias
				 */ 
				xqNav.AddNavigator(fileName, alias );                                   

				/* Copiamos el contenido del fichero de la Query
				 * en una variable interna
				 */
				string sQuery = String.Empty;

				/* Creamos el flujo */
				StreamReader sr = new StreamReader(query);
				/* Leemos el contenido y lo almacenamos */
				sQuery = sr.ReadToEnd();
				/* Cerramos el flujo */
				sr.Close();
			
				/* Compilamos la Query */
				XQueryExpression expr = new XQueryExpression(sQuery);

				/* Ejecutamos la query y mostramos los resultados */
				Console.WriteLine("Ejecutando consulta XQuery...");
				StreamWriter sw = new StreamWriter("resultados.xml",
					false,
					System.Text.Encoding.UTF8);
				sw.WriteLine("<?xml version='1.0'?>" + (expr.Execute(xqNav)).ToXml());
				sw.Close();
				/* Abrimos el fichero con los resultados */
				Process.Start("explorer.exe", "resultados.xml");
			}
			catch (Exception ex)
			{
				Console.WriteLine("Se ha producido un error: " + ex.Message);
				Console.Read();
			}
		}
	}
}

Vamos a compilar nuestro programa. Pinchamos en el menú Bulid à Build execQuery

Figura 8

En la ventana Output nos aparecerá un detalle de la compilación de nuestro programa. En el caso de que no se produzcan errores, la pantalla deberá aparecer con la siguiente información:

Figura 9 

En caso contrario nos indicará los errores que se han producido, los corregiremos y volveremos a ejecutar el paso anterior.

El fichero Xml.

Para poder ejecutar nuestro programa nos falta diseñar el fichero Xml y alguna que otra query para comprobar que nuestro programa funciona correctamente. El fichero Xml almacenará información sobre los vuelos que se realizan al cabo de un día en un aeropuerto. El fichero se llamará aeropuerto.xml y tendrá la siguiente información:

Un poco de XQuery.

Vamos a ver una pequeña introducción sobre el uso de XQuery básico, puesto que es un lenguaje muy extenso. Para conocer más a fondo este lenguaje, podemos leer documentación sobre XQuery en la página http://www.w3.org/TR/xquery/.

Vamos a ver las expresiones básicas para poder realizar consultas sobre nuestro fichero Xml:

Expresiones FLWR:

Una expresión de XQuery puede ser una expresión de XPath simple,pero los usuarios necesitan consultas más complejas para poder obtener una serie de resultados que XPath no permite.

Las consultas XQuery se forman a partir de cuatro palabras clave: FOR, LET, WHERE y RETURN. En las palabras clave de XQuery no se distinguen mayúsculasde minúsculas:

            Se emplea para recorrer todos los datos mediante una o varias variables asociadas con expresiones. 
            Las expresiones pueden ser referencias de ruta u otras expresiones XML legitimas.

La siguiente instrucción recorre todos los nodos lineaDetalle del documento:

FOR $b IN document(“aliasXml”)/aeropuerto/lineadetalle

            También puede utilizar la cláusula LET para enlazar variables. Sin embargo, a diferencia de la cláusula FOR,
            no itera. Por tanto, enlaza una variable con un valor individual de la expresión.

            La siguiente instrucción almacena en la variable $a los valoresde la lineaDetalle

                        LET $a := document("aliasXml")/aeropuerto/lineadetalle
           Es similar a la cláusula WHERE de SQL. Filtra los datos y determina cuales cumplen la condición.

La siguiente mostraría los nodos cuya compañía sea IBERIA

FOR $b IN document(“aliasXml”)/aeropuerto/lineadetalle WHERE $b/@compania = “IBERIA"

          Genera el resultado de la expresión FLWR y pueden ser valores o un patrón de nodos. Adicionalmente puede calificarse más mediante constructores de elementos, ordenación, cálculos o comparaciones. Un constructor de elementos es un elemento XML que se representa así mismo y permite generar nuevos elementos desde dentro de la consulta

Para mostrar el resultado de la instrucción anterior en un nuevo fichero XML podríamos utilizar la siguiente query <resultados> { FOR $b IN document(“aliasXml”)/aeropuerto/lineadetalle WHERE $b/@compania = “IBERIA” RETURN <resul> { $b/hora_salida } { $b/destino } </resul> } </resultados>

Las expresiones FLWR se procesan en un orden determinado. Primero se procesan las cláusulas FOR o LET, a continuación se procesan las cláusulas WHERE y, después, las clausulas RETURN.

Para profundizar en el lenguaje de consulta Xquery os recomiendo estas direcciones:

Creación de las Queries para nuestra aplicación.

La extensión de los ficheros que contienen instrucciones de XQuery es nombrequery.XQU.

Una vez visto una visión global sobre Xquery, vamos a realizar 3 consultas para procesar en nuestro programa.

1. Mostrar toda la información de los vuelos del fichero:

<resultados>
{
     FOR $b IN document("aliasXml")/aeropuerto/lineadetalle
     RETURN
     <resul>
         { $b/@compania }
         { $b/@nvuelo }
         { $b/@matricula
         { $b/@pasajeros }
         { $b/hora_salida }
         { $b/destino }
     </resul>
}
</resultados>
 
 
Lo guardamos en el directorio donde se encuentra el ejecutable (Debug/bin), con el nombre 1.xqu

Resultados

2. Mostrar la hora de salida y el destino de los vuelos que tengan un nº de pasajeros mayor que 100 y menor que 200:

<resultados>
{
    
    
    
    
     FOR $b IN document("aliasXml")/aeropuerto/lineadetalle
         
         
         
         
          WHERE $b/@pasajeros > "100" AND $b/@pasajeros < "200"
    
    
    
    
     RETURN
          <resul>
        
        
        
        
         { $b/hora_salida }
                  { $b/destino }
    
    
    
    
     </resul>
}
</resultados>

Lo guardamos en el directorio donde se encuentra el ejecutable (Debug/bin), con el nombre 2.xqu.

Resultado:

3. Mostrar el nº de aviones, media de pasajeros entre los aviones, nº máximo y mínimo de pasajeros de todos los vuelos:

<resultados>
{
    
    
    
    
     LET $a := document("aliasXml")/aeropuerto/lineadetalle
     
     
     
     
                             RETURN
    
    
    
    
     <countpas>
               
               
               
               
                { count($a/@pasajeros) }
    
    
    
    
     </countpas>
         
         
         
         
          <avgpas>
       
       
       
       
        { avg($a/@pasajeros) }
          </avgpas>
          <maxpas>
                { max($a/@pasajeros) }
          </maxpas>
          <minpas>
                { min($a/@pasajeros) }
          </minpas>
}
</resultados>

Lo guardamos en el directorio donde se encuentra el ejecutable (Debug/bin), con el nombre 3.xqu.

Resultados:

Prueba del proyecto.

Una vez creadas las Queries es hora de probar si nuestra aplicación funciona correctamente. Es imprescindible que las queries y el fichero XML estén en el directorio bin de nuestro proyecto. Pulsamos F5 (Debug à Start) desde Visual Studio .NET y nuestra aplicación arrancará, mostrando la siguiente ventana:

Figura 10

Introducimos el nombre del fichero XML y pulsamos intro

Figura 11

El nombre de la query que queremos procesar y pulsamos intro

Figura 12

A continuación nos aparecerá un fichero XML con los resultados la query. En el caso de producirse algún error, la aplicación nos informará con un mensaje por pantalla.

Conclusión:

Espero que este pequeño artículo haya valido al lector para comprender lo poderoso que puede llegar a ser este lenguaje de consulta de datos y para que se haya familiarizado con su estructura y su uso junto con Visual Studio .NET.

Bibliografía.

Presentando XQuery en sociedad Por Mariano Minoli

MSDN de Microsoft.


ir al índice

Fichero con el código de ejemplo: luis_XQuery.zip - 74.8 KB