32
votes

I am trying to read XML from stream reader and am also getting response XML. But when i try to read its nodes it is always returning 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 Document

<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>
5

5 Answers

55
votes

The XML document uses the default namespace "http://ratequote.usfnet.usfc.com/v2/x1". You need to change the SelectSingleNode call to use this namespace.

You need to setup a namspace manager and then supply it to SelectSingleNode.

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

EDIT The RateQuoteResponse element has a default namespace xmlns="...". This means that all elements use this namespace also, unless specifically overridden.

15
votes

You can remove the namespace while reading the file, just disable the namespaces on the 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");
}

After that you don't have to care about the namespace while using XPath / LINQ on your XML-elements.

9
votes

The problem is that you're asking for a RateQuote element without a namespace - whereas the RateQuote element is actually in the namespace with URI http://ratequote.usfnet.usfc.com/v2/x1.

You can either use an XmlNamespaceManager to address the namespace within your XPath, or use LINQ to XML which has very simple namespace handling:

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

Personally I would use LINQ to XML if you possibly can - I find it much more pleasant to use than XmlDocument. You can still use XPath if you want of course, but I personally prefer to use the querying methods.

EDIT: Note that the namespace defaulting applies to child elements too. So to find the TOTAL_COST element you'd need:

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

You might want to set Namespaces to false in the XmlTextReader.

So, in your code, change:

var xmlReader = new XmlTextReader(stream);

to

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

With this change, you should be able to get the node you want with SelectSingleNode without having to use namespaces.

3
votes

You should also be able to do:

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

The VB syntax for that is:

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