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

XML-документ SelectSingleNode возвращает null

Я пытаюсь читать XML из чтения потока, а также получаю ответ XML. Но когда я пытаюсь прочитать его узлы, он всегда возвращает null.

var request = (HttpWebRequest) WebRequest.Create(address);
var response = (HttpWebResponse) request.GetResponse();
var stream = response.GetResponseStream();

if(stream != null)
{
   var xmlReader = new XmlTextReader(stream);
   var xmlDocument = new XmlDocument();
   xmlDocument.Load(xmlReader);
   var node = xmlDocument.SelectSingleNode("RateQuote");
}

XML-документ

<RateQuoteResponse xmlns="http://ratequote.usfnet.usfc.com/v2/x1">
  <STATUS>
   <CODE>0</CODE>
   <VIEW>SECURED</VIEW>
   <VERSION>...</VERSION>
  </STATUS>
 <RateQuote>
   <ORIGIN>
     <NAME>KNOXVILLE</NAME>
     <CARRIER>USF Holland, Inc</CARRIER>
     <ADDRESS>5409 N NATIONAL DR</ADDRESS>
     <CITY>KNOXVILLE</CITY>
     <STATE>TN</STATE>
     <ZIP>37914</ZIP>
     <PHONE>8664655263</PHONE>
     <PHONE_TOLLFREE>8006545963</PHONE_TOLLFREE>
     <FAX>8656379999</FAX>
  </ORIGIN>
  <DESTINATION>
     <NAME>KNOXVILLE</NAME>
     <CARRIER>USF Holland, Inc</CARRIER>
     <ADDRESS>5409 N NATIONAL DR</ADDRESS>
     <CITY>KNOXVILLE</CITY>
     <STATE>TN</STATE>
     <ZIP>37914</ZIP>
     <PHONE>8664655263</PHONE>
     <PHONE_TOLLFREE>8006545963</PHONE_TOLLFREE>
     <FAX>8656379999</FAX>
  </DESTINATION>
     <ORIGIN_ZIP>37914</ORIGIN_ZIP>
     <DESTINATION_ZIP>37909</DESTINATION_ZIP>
     <TOTAL_COST>99.24</TOTAL_COST>
     <SERVICEDAYS>1</SERVICEDAYS>
     <INDUSTRYDAYS>1.6</INDUSTRYDAYS>
     <CLASSWEIGHT>
        <CLASS>55</CLASS>
        <ASCLASS>50</ASCLASS>
        <WEIGHT>100</WEIGHT>
        <CHARGES>0.0</CHARGES>
     </CLASSWEIGHT>
</RateQuote>
</RateQuoteResponse>
4b9b3361

Ответ 1

В документе XML используется пространство имен по умолчанию "http://ratequote.usfnet.usfc.com/v2/x1". Вам нужно изменить вызов SelectSingleNode для использования этого пространства имен.

Вам нужно настроить диспетчер namspace и затем отправить его на SelectSingleNode.

var nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("rate", "http://ratequote.usfnet.usfc.com/v2/x1");
var node = xmlDocument.SelectSingleNode("//rate:RateQuote", nsmgr);

ИЗМЕНИТЬ Элемент RateQuoteResponse имеет пространство имен по умолчанию xmlns="...". Это означает, что все элементы также используют это пространство имен, если только они не переопределены.

Ответ 2

Вы можете удалить пространство имен во время чтения файла, просто отключите пространства имен в XmlTextReader:

var request = (HttpWebRequest) WebRequest.Create(address);
var response = (HttpWebResponse) request.GetResponse();
var stream = response.GetResponseStream();

if(stream != null)
{
   var xmlReader = new XmlTextReader(stream);
   xmlReader.Namespaces = false;
   var xmlDocument = new XmlDocument();
   xmlDocument.Load(xmlReader);
   var node = xmlDocument.SelectSingleNode("RateQuote");
}

После этого вам не нужно заботиться о пространстве имен при использовании XPath/LINQ в ваших XML-элементах.

Ответ 3

Проблема заключается в том, что вы запрашиваете элемент RateQuote без пространства имен, тогда как элемент RateQuote фактически находится в пространстве имен с URI http://ratequote.usfnet.usfc.com/v2/x1.

Вы можете использовать XmlNamespaceManager для адресации пространства имен в вашем XPath или использовать LINQ to XML, который имеет очень простую обработку пространства имен:

var document = XDocument.Load(stream);
XNamespace ns = "http://ratequote.usfnet.usfc.com/v2/x1";
XElement rateQuote = document.Root.Element(ns + "RateQuote");

Лично я бы использовал LINQ to XML, если возможно, - я нахожу его более приятным в использовании, чем XmlDocument. Вы все равно можете использовать XPath, если хотите, но лично я предпочитаю использовать методы запросов.

РЕДАКТИРОВАТЬ: Обратите внимание, что по умолчанию для пространства имен применяется и дочерние элементы. Поэтому, чтобы найти элемент TOTAL_COST, который вам нужен:

XElement cost = document.Root
                        .Element(ns + "RateQuote")
                        .Element(ns + "TOTAL_COST");

Ответ 4

Возможно, вы захотите установить для пространств имен значение false в XmlTextReader.

Итак, в вашем коде измените:

var xmlReader = new XmlTextReader(stream);

в

var xmlReader = new XmlTextReader(stream) { Namespaces = false };

С этим изменением вы сможете получить нужный узел с помощью SelectSingleNode без использования пространств имен.

Ответ 5

Вы также сможете:

...
var node = xmlDocument["RateQuote"];
...

Синтаксис VB для этого:

...
Dim node as XmlNode = xmlDocument("RateQuote")
...