2008-10-08 8 views
19

Mam projekt, w którym biorę szczególnie brzydki "na żywo" HTML i zmuszam go do formalnego XML DOM z pakietem Agility HTML. To, co chciałbym móc zrobić, to następnie zapytać o to za pomocą Linq-a do XML-a, aby zeskrobać potrzebne mi bity. Używam metody opisanej here do parsowania HtmlDocument do XDocument, ale podczas próby kwerendy nad tym nie jestem pewien jak obsługiwać przestrzenie nazw. W jednym konkretnym dokumencie oryginalny HTML faktycznie źle sformatowane XHTML z następującym tagiem:W jaki sposób obsługiwać arbitralne przestrzenie nazw podczas kwerendy przez Linq do XML?

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

Podczas próby kwerendy z tego dokumentu wydaje się, że atrybut namespace powstrzymuje mnie od robienia czegoś jak:

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

Najwyraźniej dla znaczników "div" tylko nazwa lokalna to "div", ale właściwą nazwą znacznika jest przestrzeń nazw plus "div". Próbowałem zrobić rozeznanie w kwestii nazw XML i wydaje się, że mogę ominąć nazw przez odpytywanie w ten sposób:

var x = 
    (from x in xDoc.Descendants() 
    where x.Name.LocalName == "div" 
    select x); 
// works 

Jednak wydaje się to dość hacky roztworu i nie prawidłowo rozwiązać nazw kwestia. Jak rozumiem, odpowiedni dokument XML może zawierać wiele przestrzeni nazw, dlatego też właściwym sposobem postępowania z nim powinno być przeanalizowanie przestrzeni nazw, których szukam. Czy ktokolwiek jeszcze musiał to zrobić? Czy po prostu sprawiam, że droga do skomplikowania? Wiem, że mogłem uniknąć tego wszystkiego, po prostu trzymałem się htmlDocument i sprawdzałem z XPath, ale wolałbym raczej trzymać się tego, co wiem (Linq), jeśli to możliwe, a także wolałbym wiedzieć, że nie jestem nastawiony na kolejne obszary nazw. powiązane kwestie w dół drogi.

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

Odpowiedz

17

Korzystanie z powinno być w porządku. Nie uważam to hack w ogóle, jeśli nie obchodzi, co nazw to w

Jeśli znasz nazw chcesz i chcesz go określić można:.

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

(MSDN reference)

można również uzyskać listę wszystkich nazw stosowanych w dokumencie:

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

przypuszczam, że można używać, aby to zrobić, ale to naprawdę nie jest ani trochę mniej od hack:

var x = namespaces.SelectMany(ns=>xDoc.Root.Descendants(ns+"div")); 
+9

Jest to najbardziej irytujące w stosunku do XLINQ API :(. Byłoby miło mieć sposób, aby po prostu powiedzieć, aby zignorować przestrzenie nazw lub przynajmniej określić domyślne. – MichaelGG

2

Jeśli wiesz, że przestrzeń nazw zostanie uznany za pomocą elementu głównego XML, jak najbardziej często tak, można to zrobić:

var ns = xDoc.Root.Name.Namespace; 
var x = xDoc.Descendants(ns + "div");