在查询Linq to XML时如何处理任意名称空间?

bou*_*ard 19 html xml linq namespaces linq-to-xml

我有一个项目,我正在采取一些特别丑陋的"实时"HTML,并使用HTML Agility Pack将其强制转换为正式的XML DOM.我希望能够做的是用Linq对XML进行查询,以便我可以清除我需要的位.我正在使用此处描述的方法将HtmlDocument解析为XDocument,但在尝试查询时我不知道如何处理命名空间.在一个特定的文档中,原始HTML实际上是格式不正确的XHTML,带有以下标记:

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
Run Code Online (Sandbox Code Playgroud)

当试图从这个文档中查询时,似乎命名空间属性阻止我做类似的事情:

var x = xDoc.Descendants("div");
// returns null
Run Code Online (Sandbox Code Playgroud)

显然,对于那些"div"标签,只有LocalName是"div",但正确的标签名称是名称空间加上"div".我试图对XML命名空间的问题进行一些研究,似乎我可以通过这种方式来绕过命名空间:

var x = 
    (from x in xDoc.Descendants()
     where x.Name.LocalName == "div"
     select x);
// works
Run Code Online (Sandbox Code Playgroud)

但是,这似乎是一个相当hacky的解决方案,并没有正确解决名称空间问题.据我所知,一个正确的XML文档可以包含多个名称空间,因此处理它的正确方法应该是解析我正在查询的名称空间.还有其他人不得不这样做吗?我只是想让它变得复杂吗?我知道我可以通过坚持使用HtmlDocument并使用XPath查询来避免所有这些,但如果可能的话,我宁愿坚持我所知道的(Linq),我也更愿意知道我没有为更进一步的命名空间做好准备 - 相关问题在路上.

在这种情况下处理命名空间的正确方法是什么?

Mar*_*ade 17

使用LocalName应该没问题.如果你不关心它的命名空间,我根本不认为它是一个黑客.

如果您知道所需的命名空间并且想要指定它,则可以:

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

(MSDN参考)

您还可以获取文档中使用的所有命名空间的列表:

var namespaces = (from x in xDoc.Root.DescendantsAndSelf()
                  select x.Name.Namespace).Distinct();
Run Code Online (Sandbox Code Playgroud)

我想你可以用它来做到这一点,但它实际上不是一个黑客:

var x = namespaces.SelectMany(ns=>xDoc.Root.Descendants(ns+"div"));
Run Code Online (Sandbox Code Playgroud)

  • 这是关于XLINQ API最烦人的事情:(.有一种方法可以告诉它忽略命名空间,或者至少指定一个默认值. (9认同)