Как вы обрабатываете произвольные пространства имен при запросе Linq на XML?
У меня есть проект, в котором я беру какой-то особенно уродливый "живой" HTML и заставляю его в формальный XML DOM с пакетом Agility Pack. То, что я хотел бы сделать, - это запросить это с помощью Linq для 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), если это возможно, и я также предпочел бы знать, что я не настроюсь на дальнейшее пространство имен - связанных с этим.
Каков правильный способ работы с пространствами имен в этой ситуации?
Ответы
Ответ 1
Использование 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"));
Ответ 2
Если вы знаете, что пространство имен будет объявлено корневым элементом XML, как это чаще всего, вы можете сделать это:
var ns = xDoc.Root.Name.Namespace;
var x = xDoc.Descendants(ns + "div");
Ответ 3
Я думаю, что ваш Google-fu вам не удалось:
http://www.google.com.au/search?hl=en&q=linq+xml+namespaces