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