Подтвердить что ты не робот

Как вы обрабатываете произвольные пространства имен при запросе 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), если это возможно, и я также предпочел бы знать, что я не настроюсь на дальнейшее пространство имен - связанных с этим.

Каков правильный способ работы с пространствами имен в этой ситуации?

4b9b3361

Ответ 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");