Inicio > .NET Framework, C#, Resolución de problemas > El método SelectNodes regresa una lista vacía tras una consulta con XPath

El método SelectNodes regresa una lista vacía tras una consulta con XPath


Ando haciendo un programa para descargar perfiles de usuarios en SharePoint (el cual espero publicar pronto en la galería de código de MSDN). Uno de los requerimientos del programa consiste en usar un WebService y descargar un XML como el siguiente:

<GetUserCollectionFromWeb xmlns="http://schemas.microsoft.com/sharepoint/soap/directory/">
<Users>
 <User ID="190" LoginName="dominio\nombre1" Email="nombre1@dominio.com.mx" />
 <User ID="111" LoginName="dominio\nombre2" Email="nombre2@dominio.com.mx" />
 </Users>
 </GetUserCollectionFromWeb>

Así pues, parte de la lógica consiste en iterar sobre cada elemento de <Users> y mostrarlo en una cuadrícula (GridView) de Windows Forms. Easy peasy, dado que el servicio web me regresa un XML, se me ocurre hacerlo con XPath. Este es mi código inicial.

XmlNode mainNode = webService.GetUserCollectionFromWeb();

string xpath = "GetUserCollectionFromWeb/Users/descendant::User";
XmlNodeList userNodes = mainNode.SelectNodes(xpath);
foreach (XmlNode userNode in userNodes)
{
    string loginName = userNode.Attributes["LoginName"].Value;
    // hacer algo con loginName;
}

Sin embargo, al hacer la prueba, el método SelectNodes me regresaba 0 elementos. Mala cosa, digo yo. Estuve revisando un rato, hasta que me decidí a hacer una pregunta en el foro de C# de MSDN. Y como siempre, obtuve apoyo para resolver el problema.

En primer lugar, he de decir, me apoyaron con la consulta XPath, ya que yo la tenía diferente. Aún con ese cambio, SelectNodes se negaba a cooperar. Fue entonces que encontramos la respuesta: el XML en cuestión tiene un espacio de nombres por defecto, xmlns, sobrescrito. Luego, hay que añadir un XmlNamespaceManager que lo contenga. Pero para crear una instancia de dicha clase, hay que pasarle al constructor un XmlNameTable, y la forma más sencilla es mediante un XmlDocument. Una vez creado, hay que añadir el espacio de nombres en cuestión y ponerle un prefijo cualquiera (en este caso, opté por “defns”). Acto seguido, modificamos el XPath y prefijamos los elementos (en mi caso, por ejemplo, cambiamos Users por defns:Users, y así). Y por último, llamamos a SelectNodes y pasamos como segundo parámetro el XmlNamespaceManager creado con anterioridad.

Y así quedó el código:

XmlNode mainNode = webService.GetUserCollectionFromWeb();

XmlDocument doc = new XmlDocument();
doc.LoadXml(mainNode.OuterXml);
XmlNamespaceManager nsmgr = new XmlNamespaceManager(mainNode.OwnerDocument.NameTable);
nsmgr.AddNamespace("defns", "http://schemas.microsoft.com/sharepoint/soap/directory/");

XmlNodeList userNodes = doc.SelectNodes("defns:GetUserCollectionFromWeb/defns:Users/descendant::defns:User", nsmgr);
foreach (XmlNode userNode in userNodes)
{
    string loginName = userNode.Attributes["LoginName"].Value;
    // hacer algo con loginName;
}

¡Y voilá! Muchas gracias a Pedro Hurtado por el apoyo, y como siempre, a Leandro Tuttini por sus valiosas contribuciones.

Categorías:.NET Framework, C#, Resolución de problemas Etiquetas: ,
  1. Aún no hay comentarios.
  1. No trackbacks yet.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s