html - namespace - ¿Cómo manejas espacios de nombres arbitrarios cuando consultas sobre Linq a XML?
xml linq namespace prefix (3)
Creo que tu Google-fu te falla:
Tengo un proyecto en el que estoy tomando un HTML "en vivo" particularmente feo y forzándolo a un DOM XML formal con el HTML Agility Pack. Lo que me gustaría poder hacer es consultar sobre esto con Linq a XML para que pueda raspar los bits que necesito. Estoy usando el método descrito aquí para analizar el HtmlDocument en un XDocument, pero cuando intento consultar sobre esto, no estoy seguro de cómo manejar los espacios de nombres. En un documento en particular, el HTML original era en realidad XHTML mal formateado con la siguiente etiqueta:
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
Al intentar consultar desde este documento, parece que el atributo del espacio de nombres me impide hacer algo como:
var x = xDoc.Descendants("div");
// returns null
Aparentemente para esas etiquetas "div" solo el LocalName es "div", pero el nombre de la etiqueta adecuada es el espacio de nombres más "div". Intenté investigar sobre el tema de los espacios de nombres XML y parece que puedo eludir el espacio de nombres al consultar de esta manera:
var x =
(from x in xDoc.Descendants()
where x.Name.LocalName == "div"
select x);
// works
Sin embargo, esto parece una solución bastante hacky y no aborda correctamente el problema del espacio de nombres. Según tengo entendido, un documento XML adecuado puede contener múltiples espacios de nombres y, por lo tanto, la forma correcta de manejarlo debería ser analizar los espacios de nombres bajo los que estoy consultando. ¿Alguien más ha tenido que hacer esto alguna vez? ¿Acabo de llegar a complicado? Sé que podría evitar todo esto simplemente quedándome con HtmlDocument y consultando con XPath, pero preferiría ceñirme a lo que sé (Linq) si es posible, y también preferiría saber que no me estoy preparando para más espacio de nombres. temas relacionados en el futuro.
¿Cuál es la forma correcta de tratar con los espacios de nombres en esta situación?
Si sabe que el elemento raíz del XML va a declarar el espacio de nombres, como suele ser el caso, puede hacer esto:
var ns = xDoc.Root.Name.Namespace;
var x = xDoc.Descendants(ns + "div");
Usar LocalName
debería estar bien. No lo consideraría un hack si no te importa en qué espacio de nombres está.
Si conoce el espacio de nombre que desea y desea especificarlo, puede:
var ns = "{http://www.w3.org/1999/xhtml}";
var x = xDoc.Root.Descendants(ns + "div");
También puede obtener una lista de todos los espacios de nombres utilizados en el documento:
var namespaces = (from x in xDoc.Root.DescendantsAndSelf()
select x.Name.Namespace).Distinct();
Supongo que podrías usar eso para hacer esto, pero en realidad no es menos hackeo:
var x = namespaces.SelectMany(ns=>xDoc.Root.Descendants(ns+"div"));