Jak radzisz sobie z dowolnymi przestrzeniami nazw podczas zapytań o Linq do XML?

Mam projekt, w którym biorę jakiś szczególnie brzydki" żywy " HTML i zmuszam go do formalnego XML DOM za pomocą Html Agility Pack. To, co chciałbym móc zrobić, to zapytać o to za pomocą Linq do XML, aby móc zeskrobać bity, których potrzebuję. Używam metody opisanej tutaj , aby przetworzyć HtmlDocument do XDocument, ale podczas próby zapytania nad tym nie jestem pewien, jak obsługiwać przestrzenie nazw. W jednym konkretnym dokumencie oryginalny HTML był właściwie słabo sformatowany XHTML z następującym tagiem:

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">

Podczas próby zapytania z tego dokumentu wydaje się, że atrybut przestrzeni nazw uniemożliwia mi zrobienie czegoś takiego jak:

var x = xDoc.Descendants("div");
// returns null

Widocznie dla tych znaczników" div "tylko LocalName to" div", ale właściwa nazwa znacznika to przestrzeń nazw plus"div". Próbowałem zrobić trochę badań nad kwestią przestrzeni nazw XML i wydaje się, że mogę ominąć przestrzeń nazw, pytając w ten sposób:

var x = 
    (from x in xDoc.Descendants()
     where x.Name.LocalName == "div"
     select x);
// works
[[3]} jednak wydaje się to raczej hacky solution i nie rozwiązuje poprawnie problemu z przestrzenią nazw. Jak rozumiem, poprawny dokument XML może zawierać wiele przestrzeni nazw, a zatem właściwym sposobem obsługi tego powinno być przeanalizowanie przestrzeni nazw, pod którymi odpytywam. Czy ktoś jeszcze musiał to robić? Czy ja tylko komplikuję sprawę? Wiem, że mógłbym uniknąć tego wszystkiego, po prostu trzymając się HtmlDocument i pytając z XPath, ale wolałbym trzymać się tego, co wiem (Linq), jeśli to możliwe i też wolałbym aby wiedzieć, że nie ustawiam się na dalsze kwestie związane z przestrzenią nazw w dół drogi.

Jaki jest właściwy sposób radzenia sobie z przestrzeniami nazw w tej sytuacji?

Author: bouvard, 2008-10-08

3 answers

Używanie LocalName powinno być w porządku. Nie uznałbym tego za włamanie, jeśli nie obchodzi cię, w jakiej przestrzeni nazw jest.

Jeśli znasz żądaną przestrzeń nazw i chcesz ją określić, możesz:

var ns = "{http://www.w3.org/1999/xhtml}";
var x  = xDoc.Root.Descendants(ns + "div");

(MSDN reference )

Możesz również uzyskać listę wszystkich przestrzeni nazw używanych w dokumencie:

var namespaces = (from x in xDoc.Root.DescendantsAndSelf()
                  select x.Name.Namespace).Distinct();

Przypuszczam, że można to wykorzystać do tego, ale to nie jest tak naprawdę mniej hack:

var x = namespaces.SelectMany(ns=>xDoc.Root.Descendants(ns+"div"));
 17
Author: Mark Cidade,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-08 16:12:34

Jeśli wiesz, że przestrzeń nazw zostanie zadeklarowana przez główny element XML, jak to najczęściej bywa, możesz to zrobić:

var ns = xDoc.Root.Name.Namespace;
var x = xDoc.Descendants(ns + "div");
 2
Author: StriplingWarrior,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-06 16:57:59
 -11
Author: piers7,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-08 15:34:14