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

时间:2008-10-08 15:29:34

标签: html xml linq namespaces linq-to-xml

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

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

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

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

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

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

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

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

3 个答案:

答案 0 :(得分:17)

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

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

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

MSDN reference

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

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

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

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

答案 1 :(得分:2)

如果您知道命名空间将由XML的根元素声明,通常情况下,您可以这样做:

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

答案 2 :(得分:-11)

我认为你的Google-fu让你失望:

http://www.google.com.au/search?hl=en&q=linq+xml+namespaces