Espacios de Nombre (namespace) y Consultas XPATH en C#

Por José Alfredo García Guirado

Contenido

 1. Introducción
 2. Consultas de Ficheros XML sin Espacios de Nombre declarados
 3. Consultas de Ficheros XML con un Espacio de Nombre y Prefijos declarados
 4. Consultas de Ficheros XML con varios Espacios de Nombre y Prefijos declarados
 5. Consultas de Ficheros XML con un Espacio de Nombre por defecto (sin Prefijo declarado)
 6. Conclusión

1. Introducción

En este artículo se describe cómo realizar consultas XPATH en ficheros XML con espacio de nombre con prefijos o sin prefijo definido (default namespace). Se ofrecen ejemplos para cada caso.

El XML como formato de elección de datos es un hecho actual. Por lo que saber ejecutar consultas sobre él se ha convertido en una necesidad imperiosa para todos; no solo aquéllos que deben consultar una base de datos formal, sino también para el manejo del fichero de configuración de nuestra aplicación o la lectura de los despachos de prensa de un sitio web o creando nuestro propio programa de manejo de snippet. Una de las formas más poderosas de hacer consultas simples en un XML es sin duda las expresiones XPATH que nos permiten llegar a cualquier nodo o nodos de nuestra jerarquía XML con una sola consulta.

Este artículo no pone énfasis en XPATH sino en el uso de XPATH en ficheros XML descriptos con espacios de nombre, y cómo adecuar nuestra expresión XPATH a dichos ficheros.

Para ello se mostrarán ejemplos de código que expliquen para cada caso cómo usar una sencilla expresión XPATH en el enredado mundo de los espacios de nombre.

 

2. Consultas de Ficheros XML sin Espacios de Nombre declarados

Primero veamos un sencillo ejemplo de XPATH sobre un fichero XML sin espacio de nombre; naturalmente que esto no es lo que queremos saber, pero para explicar mejor el uso con espacio de nombre no hay nada mejor, a mi juicio, que explicar el caso más simple de fichero, que es aquél sin espacio de nombre.

A continuación se lista el fragmento de un fichero XML que utilizaremos para esta sección:

<?xml version="1.0" encoding="utf-8" ?> 
<autos>
      <auto>
            <fabricante>Hyundai</fabricante>
            <color>plateado</color>
            <modelo>Santa Fe</modelo>
            <anno>2004</anno>
            <ruedas>
                  <diametro>17</diametro>
                  <color>negro</color>
            </ruedas>
      </auto>
</autos>

Observa que este código no posee espacio de nombres. Este tipo de estructura XML es típico de ficheros de configuración o de consultas de información. Como nuestro énfasis no está puesto en cómo hacer un XPATH, el fichero esta simplificado a un solo ítem auto.

Si queremos saber por ejemplo el color de los neumáticos de nuestro auto podemos implementar el siguiente sencillo XPATH:

"autos/auto/ruedas/color"

Y usaríamos el siguiente fragmento de código para realizar la lectura:

xdoc.Load(xmlFullFileName);
//Aplicando XPATH a el documento creado.....
XmlNodeList xnodes = xdoc.SelectNodes(“autos/auto/ruedas/color”);
//Impimiendo los resultados obtenidos
Console.WriteLine();
for (int i = 0; i < xnodes.Count;i++)
{
      Console.WriteLine(xnodes[i].InnerText);
}

Este código devolvería impreso en la consola "negro", que es el contenido del nodo <color> dentro de <ruedas>.

Este es un caso típico de uso de XPATH y usualmente no ofrece ninguna complicación implementarlo. Veamos en el siguiente párrafo, cuando entra a jugar un espacio de nombre.

 

3. Consultas de Ficheros XML con un Espacio de Nombre y Prefijos declarados

Aquí presentamos nuestro ejemplo con un espacio de nombre declarado. Muchas veces se utilizan direcciones Web para declarar estos espacios de nombre con el fin de que sean únicos y, por casualidad, no se igualen dos nombres. Para nuestro caso vamos a definir el namespace http://jgarcia.g-softsolutions.de/XmlXpath:

<?xml version="1.0" encoding="utf-8" ?> 
<autos xmlns:pre="http://jgarcia.g-softsolutions.de/XmlXpath">
      <pre:auto>
            <fabricante>Hyundai</fabricante>
            <color>plateado</color>
            <modelo>Santa Fe</modelo>
            <anno>2004</anno>
            <ruedas>
                  <pre:diametro>17</pre:diametro>
                  <pre:color>negro</pre:color>
            </ruedas>
      </pre:auto>
</autos>

Observa que al espacio de nombre se le asignó un prefijo arbitrario (pre, en este ejemplo). Esto señala que los nodos XML que estén marcados con pre pertenecerán a este espacio de nombre y los otros no. Esto tiene interesantes aplicaciones que no detallaremos aquí. Solo nos centraremos en cómo leer el color de nuestras ruedas en esta nueva situación. Si probamos con nuestro XPATH anterior veremos que no retornará ningún resultado si lo aplicamos a este fichero XML.

"autos/auto/ruedas/color" | Sin coincidencias

Para poder leer en este fichero XML usando XPATH necesitamos tomar en cuenta el espacio de nombre; de esta manera, nuestro XPATH debe tomar la siguiente estructura:

"autos/pre:auto/ruedas/pre:color"

Observa que los nodos que están con el prefijo en el XML tienen que estar de la misma forma en el XPATH; de otro modo no serán leidos y la pregunta regresará vacia.

Pero además tenemos que informarle al compilador que vamos a usar espacios de nombre. Afortunadamente, las versiones 1 y 2 del .Net framework poseen una clase para manejar esto. Nuestro código tendría que ser el siguiente:

xdoc.Load(xmlFullFileName);
System.Xml.XmlNamespaceManager xmlmanager = new XmlNamespaceManager(xdoc.NameTable);
xmlmanager.AddNamespace("pre", "http://jgarcia.g-softsolutions.de/XmlXpath");
XmlNodeList xnodesl = xdoc.SelectNodes("autos/pre:auto/ruedas/pre:color",xmlmanager);
//Impimiendo los resultados obtenidos
Console.WriteLine();
for (int i = 0; i < xnodesl.Count;i++)
{
       Console.WriteLine(xnodesl[i].InnerText);
}

Observa la clase XmlNameSpaceManager, esta clase se encarga de identificar el o los espacios de nombre existentes en el documento XML, de tal forma que cuando se utilice la expresión XPATH los prefijos estén identificados.

Un Query con XPATH en ficheros con espacios de nombre, sin utilizar esta clase, termina en un resultado vacío.

 

4. Consultas de Ficheros XML con varios Espacios de Nombre y Prefijos declarados

La siguiente combinación que se nos puede presentar es un fichero con varios espacios de nombre; no son frecuentes, pero existen; sirven para poder, por ejemplo, tener nodos iguales pero que se puedan extraer diferenciándolos por el espacio de nombre. Veamos nuestro pequeño fichero XML con algunas modificaciones para ilustrar este ejemplo:

<?xml version="1.0" encoding="utf-8" ?> 
<autos xmlns:pre="http://jgarcia.g-softsolutions.de/standard"
         xmlns:lux="http://jgarcia.g-softsolutions.de/luxed"> 
<auto>
            <fabricante>Hyundai</fabricante>
            <color>plateado</color>
            <modelo>Santa Fe</modelo>
            <anno>2004</anno>
            <pre:ruedas>
                  <diametro>17</diametro>
                  <color>negro</color>
            </pre:ruedas>
            <lux:ruedas>
                  <diametro>17</diametro>
                  <color>blanco</color>
            </lux:ruedas>
      </auto>
</autos>

En el ejemplo el fichero posee dos espacios de nombre: uno para definir una configuración estándar del auto, y otro para ruedas de lujo.

Empezemos en este caso por el código; el mismo es muy parecido al ejemplo anterior, solamente necesitamos asignar al manejador de espacios de nombre los dos espacios de nombre creados, como se ve a continuación:

xdoc.Load(xmlFullFileName);
System.Xml.XmlNamespaceManager xmlmanager = new XmlNamespaceManager(xdoc.NameTable);
xmlmanager.AddNamespace("pre", "http://jgarcia.g-softsolutions.de/standard");
xmlmanager.AddNamespace("lux", "http://jgarcia.g-softsolutions.de/luxus");
                    XmlNodeList xnodesl =
xdoc.SelectNodes("autos/auto/lux:ruedas/color",xmlmanager);
//Impimiendo los resultados obtenidos
Console.WriteLine();
for (int i = 0; i < xnodesl.Count;i++)
{
       Console.WriteLine(xnodesl[i].InnerText);
}

Ahora, si hacemos un "SelectNodes" sobre el fichero XML, por ejemplo con el programa anterior y el XPATH:

"autos/auto/lux:ruedas/color" | Obtendremos como resultado = blanco.

Si hacemos la misma operación con:

"autos/auto/pre:ruedas/color" | Obtendremos como resultado = negro.

Como puedes observar, la manipulación de espacios de nombre es relativamente sencilla cuando se conoce su significado.

 

5. Consultas de Ficheros XML con un Espacio de Nombre por defecto (sin Prefijo declarado)

Esta es quizás la situación más engañosa que se puede presentar; y es además una situación frecuente. En el caso de querer aplicar el espacio de nombres a todo el XML muchas veces se omite el prefijo y se codifica el espacio de nombre de forma que signifique que cada nodo del fichero pertenecerá a dicho espacio de nombres. En este caso no es necesario ponerle prefijo al fichero.

Veamos el siguiente fichero ejemplo:

<?xml version="1.0" encoding="utf-8" ?> 
<autos xmlns="http://jgarcia.g-softsolutions.de/default">
<auto>
            <fabricante>Hyundai</fabricante>
            <color>plateado</color>
            <modelo>Santa Fe</modelo>
            <anno>2004</anno>
            <ruedas>
                  <diametro>17</diametro>
                  <color>negro</color>
            </ruedas>
      </auto>
</autos>

Observa que la declaración del espacio de nombre no tiene asignado ningún prefijo:

<autos xmlns="http://jgarcia.g-softsolutions.de/default">

Mientras que en las anteriores declaraciones existe el mismo:

<autos xmlns:pre="http://jgarcia.g-softsolutions.de/standard"

Entonces, ¿Cómo hacer? Lo más lógico sería que funcionara un XPATH sin prefijos, pero no lo hace. La otra idea es asignar el espacio de nombre mediante la clase XmlNameSpaceManager y hacer el XPATH sin prefijos. Bien, eso tampoco funciona.

La solución no es obvia. Se requieren dos pasos:

  1. Crear el XmlSpaceManager y asignarle el espacio de nombre. En el método de asignación, usar un prefijo arbitrario (en nuestro ejemplo "def").

  2. Colocar delante de cada nodo de la expresión XPATH el prefijo usado. Para nuestro ejemplo, leeremos el modelo del auto:

    "def:autos/def:auto/def:modelo", que devolverá "Santa Fe".

Veamos esto en código:

xdoc.Load(xmlFullFileName);
System.Xml.XmlNamespaceManager xmlmanager = new XmlNamespaceManager(xdoc.NameTable);
xmlmanager.AddNamespace("def", "http://jgarcia.g-softsolutions.de/default");
XmlNodeList xnodesl = xdoc.SelectNodes("def:autos/def:auto/def:modelo",xmlmanager);
//Impimiendo los resultados obtenidos
Console.WriteLine();
for (int i = 0; i < xnodesl.Count;i++)
{
       Console.WriteLine(xnodesl[i].InnerText);
}

 

6. Conclusión

En el artículo se ilustra cómo trabajar fácilmente con las expresiones XPATH y los espacios de nombre. Aunque en la mayoría de los casos es posible seguir una lógica en el funcionamiento del XPATH y los referidos espacios, esto no es tan obvio cuando se usa el espacio de nombres por defecto.

En el artículo no se profundiza sobre la utilidad que tienen dichos espacios de nombre no solo para el filtraje de las "queries" sobre el fichero XML, sino como parte del sistema de validación de dichos ficheros.

Los ejemplos han sido ejecutados en Visual Studio 2003 y Visual Studio 2005 Beta, por lo que deben ser válidos para la versión definitiva del .Net framework 2.0.

Bb972273.jose_alfredo_garcia_guirado(es-es,MSDN.10).gif José Alfredo García Guirado trabajó 10 años como profesional independiente en Buenos Aires, Argentina, y desde 2002 como desarrollador .net independiente en Bad Honnef, Alemania. Terminó sus estudios de Ingeniería Electrónica, especialidad Máquinas Computadoras, en el Instituto Superior Politécnico ISPJAE de La Habana, Cuba, en 1982. Fue Investigador Agregado en el Instituto de Cibernética, Matemática y Física (ICIMAF) de la Academia de Ciencias de Cuba hasta 1989, y Profesor Auxiliar Agregado de la ISPJAE durante 1992 y 1993. Es MCP desde 1999 y MCSE desde 2000; MCSA 2002 y MCAD 2005. Nació en 1959 en La Habana.