2008-10-08 6 views
19

Ich habe ein Projekt, in dem ich etwas besonders hässliches "Live" HTML nehme und es mit dem HTML Agility Pack in ein formelles XML DOM erzwinge. Ich möchte dann mit Linq nach XML abfragen, damit ich die benötigten Bits auskratzen kann. Ich verwende die beschriebene Methode here, um das HtmlDocument in ein XDocument zu analysieren, aber wenn ich versuche, darüber abzufragen, bin ich nicht sicher, wie man Namespaces handhabt. In einem bestimmten Dokument wurde die ursprüngliche HTML tatsächlich schlecht XHTML mit dem folgenden Tag formatiert:Wie behandeln Sie willkürliche Namespaces bei der Abfrage von Linq nach XML?

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

Beim Versuch, aus diesem Dokument zu fragen scheint es, dass das Namespace-Attribut mich daran hindert, etwas zu tun:

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

Anscheinend für diese "div" -Tags ist nur der LocalName "div", aber der richtige Tag-Name ist der Namespace plus "div". Ich habe versucht, einige der Forschung über die Ausgabe von XML-Namespaces zu tun und es scheint, dass ich den Namespace durch Abfragen auf diese Weise umgehen kann:

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

Allerdings scheint dies wie eine ziemlich hacky Lösung und die Adresse nicht richtig den Namespace Problem. So wie ich es verstehe, kann ein korrektes XML-Dokument mehrere Namespaces enthalten und daher sollte die richtige Vorgehensweise darin bestehen, die Namespaces, unter denen ich abfrage, zu analysieren. Hat sonst noch jemand das tun müssen? Mache ich es einfach zu kompliziert? Ich weiß, dass ich all das vermeiden konnte, indem ich einfach bei HtmlDocument blieb und mit XPath abfragte, aber ich würde lieber bei dem bleiben, was ich weiß (Linq) wenn möglich und ich würde auch gerne wissen, dass ich mich nicht für weitere Namespaces aufriche. verwandte Probleme auf der Straße.

Wie ist der richtige Umgang mit Namespaces in dieser Situation?

Antwort

17

Verwenden LocalName sollte in Ordnung sein. Ich würde es nicht einen Hack betrachten überhaupt, wenn Sie kümmern sich nicht, welche Namespace ist es in

Wenn Sie den Namespace weiß, Sie wollen, und Sie wollen es spezifizieren, können Sie:.

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

(MSDN reference)

Sie auch eine Liste aller Namensräume erhalten können im Dokument verwendet:

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

ich nehme an, dass dies zu tun, verwenden könnte, aber es ist nicht wirklich weniger ein Hack:

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

Dies ist die nervigste Sache über die XLINQ API :(. Es wäre schön, eine Möglichkeit zu haben, Namespaces zu ignorieren oder zumindest einen Standard anzugeben. – MichaelGG

2

Wenn Sie wissen, dass der Namensraum durch das Wurzelelement des XML erklärt werden wird, wie die meisten oft der Fall, können Sie dies tun:

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