19

我有一个项目,我正在使用一些特别丑陋的“实时”HTML,并使用 HTML Agility Pack 将其强制转换为正式的 XML DOM。然后我想要做的是使用 Linq to XML 查询这个,以便我可以刮出我需要的位。我正在使用此处描述的方法将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

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

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

4

3 回答 3

17

使用LocalName应该没问题。如果您不在乎它在哪个名称空间中,我根本不会认为它是一种黑客行为。

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

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

MSDN 参考

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

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

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

var x = namespaces.SelectMany(ns=>xDoc.Root.Descendants(ns+"div"));
于 2008-10-08T15:32:10.113 回答
2

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

var ns = xDoc.Root.Name.Namespace;
var x = xDoc.Descendants(ns + "div");
于 2012-08-06T16:57:59.540 回答
-11

我认为您的 Google-fu 让您失望了:

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

于 2008-10-08T15:34:14.820 回答