XDocument и Linq возвращают ноль, если элемент имеет атрибут xmlns - PullRequest
22 голосов
/ 09 мая 2011

Новичок с XDocuments и Linq, пожалуйста, предложите решение для извлечения данных из определенного тега в строке xml:

Если у меня есть XML-строка из ответа веб-службы (я отформатировал xml для простоты):

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap:Body>
    <GetCashFlowReportResponse xmlns="http://tempuri.org/">
      <GetCashFlowReportPdf>Hello!</GetCashFlowReportPdf>
    </GetCashFlowReportResponse>
  </soap:Body>
</soap:Envelope>

Используя следующий код, я могу получить значение, только если тег GetCashFlowReportResponse не имеет атрибута "xmlns". Не уверен почему? Иначе, это всегда возвращает нуль.

string inputString = "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><soap:Body><GetCashFlowReportResponse xmlns=\"http://tempuri.org/\"><GetCashFlowReportPdf>Hello!</GetCashFlowReportPdf></GetCashFlowReportResponse></soap:Body></soap:Envelope>"    
XDocument xDoc = XDocument.Parse(inputString);
//XNamespace ns = "http://tempuri.org/";
XNamespace ns = XNamespace.Get("http://tempuri.org/");

var data = from c in xDoc.Descendants(ns + "GetCashFlowReportResponse")
           select (string)c.Element("GetCashFlowReportPdf");

foreach (string val in data)
{
    Console.WriteLine(val);
}

Я не могу изменить веб-сервис для удаления этого атрибута. Есть ли лучший способ прочитать ответ и вернуть фактические данные пользователю (в более читаемой форме)?

Отредактировано: РЕШЕНИЕ:

XDocument xDoc = XDocument.Parse(inputString);
XNamespace ns = "http://tempuri.org/";

var data = from c in xDoc.Descendants(ns + "GetCashFlowReportResponse")
           select (string)c.Element(ns + "GetCashFlowReportPdf");
foreach (string val in data)
{
   Console.WriteLine(val);
}

Примечание. Даже если все дочерние элементы не имеют атрибута пространства имен, код будет работать, если вы добавите к элементу "ns", так как я полагаю, что потомки наследуют пространство имен от родителя (см. Ответ от SLaks).

Ответы [ 3 ]

15 голосов
/ 09 мая 2011

Вам необходимо включить пространство имен:

XNamespace ns = "http://tempuri.org/";

xDoc.Descendants(ns + "GetCashFlowReportResponse")
2 голосов
/ 09 мая 2011

Просто запросите элементы, используя полные имена:

// create a XML namespace object
XNamespace ns = XNamespace.Get("http://tempuri.org/");

var data = from c in xDoc.Descendants(ns + "GetCashFlowReportResponse")
           select (string)c.Element(ns + "GetCashFlowReportPdf");

Обратите внимание на использование перегруженного оператора +, который создает QName с пространством имен XML и локальной строкой имени.

2 голосов
/ 09 мая 2011
XName qualifiedName = XName.Get("GetCashFlowReportResponse", 
    "http://tempuri.org/");

var data = from d in xDoc.Descendants(qualifiedName)
...