我有一个项目,我正在使用一些特别难看的“实时”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),我也更愿意知道我没有为更进一步的命名空间做好准备 - 相关问题。
在这种情况下处理命名空间的正确方法是什么?
答案 0 :(得分:17)
使用LocalName
应该没问题。如果你不关心它的命名空间,我根本不认为它是黑客。
如果您知道所需的命名空间并且想要指定它,则可以:
var ns = "{http://www.w3.org/1999/xhtml}";
var x = xDoc.Root.Descendants(ns + "div");
您还可以获取文档中使用的所有命名空间的列表:
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让你失望: