I'm calling a WebService exposed by Oracle that accepts an input of an ItemID and returns to me the corresponding Item Number. I want to grab the Item Number that has been returned out of the XML contained in the response.

The XML looks like this:

<env:Envelope 
 
xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" 
 
xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 
xmlns:ns0="http://dev1/MyWebService1.wsdl"> 
 
<env:Header> 
 
<wsse:Security 
   
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" 
   
xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" 
   
xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" 
   
env:mustUnderstand="1"/> 
 
</env:Header> 
 
<env:Body> 
 
<ns0:getItemNbrByItemIdResponseElement> 
   
<ns0:result>1010603</ns0:result> 
 
</ns0:getItemNbrByItemIdResponseElement> 
 
</env:Body> 
</env:Envelope> 

I'm interested in grabbing only the <ns0:result>1010603</ns0:result> particularly only the 1010603.

I haven't done a lot of work parsing XML using C# and I'm playing around with a few different methods so far. What is the recommended way to do this?

I'm on VS2008 (so XPath is available etc.)

link|flag

6 Answers

up vote 12 down vote accepted

I'd personally use LINQ to XML, because I find that easier to deal with than XPath, particularly when namespaces are involved. You'd do something like:

XNamespace ns0 = "http://dev1/MyWebService1.wsdl"; 
 
String result = doc.Descendants(ns0 + "result").First().Value; 

Note that doc here is expected to be an XDocument, not an XmlDocument. (My guess is that this is why it wasn't showing up for you.)

link|flag
Agreed; without LINQ you'd need to use namespace-managers and all sorts - this is much simpler. – Marc Gravell Dec 17 '08 at 14:50
"need" is a strong word :) – annakata Dec 17 '08 at 15:00
+1, namespaces "need" to be easier to work with which XLINQ does nicely – sixlettervariables Dec 17 '08 at 15:12
When trying to use this VS is complaining about the .Descendants method. Despite having using System.Linq and System.Xml.Linq present. Any thoughts/what I'm missing? I certainly like how concise this solution is. – Mat Nadrofsky Dec 17 '08 at 15:15
@Mat: Will update the answer. – Jon Skeet Dec 17 '08 at 15:26
show 2 more comments

If you don't want to go for Linq you could use XPathDocument to retrieve the value:

XPathDocument xmldoc = new XPathDocument(@"C:tmpsample.xml"); 
XPathNavigator nav = xmldoc.CreateNavigator(); 
 
XmlNamespaceManager nsMgr = new XmlNamespaceManager(nav.NameTable); 
nsMgr
.AddNamespace("ns0", "http://dev1/MyWebService1.wsdl"); 
 
XPathNavigator result = nav.SelectSingleNode("//ns0:result", nsMgr); 
System.Diagnostics.Debug.WriteLine(result.Value); 

XPathDocument has a lower memory footprint and is most likely faster in your scenario than XmlDocument. XmlDocument builds up a complete object model of your XML document in memory whereas XPathDocument does not do that.

link|flag
This one is working quite well. :) Thanks for the post! – Mat Nadrofsky Dec 17 '08 at 15:07

fwiw you can cheat the namespace issue with an xpath like this: //*[local-name()='result']

link|flag
this is much more elegant than the chosen Answer. – Zahir Jun 22 '09 at 8:11

Off the top of my head, the following should work:

XmlDocument doc = new XmlDocument(); 
doc
.PreserveWhitespace = true; 
 
XmlNamespaceManager mgr = GetNamespace(doc); 
doc
.LoadXml(xmltext); 
 
XmlNode nd = doc.DocumentElement.SelectSingleNode("//ns0:result", mgr); 

The namespace code looks like this:

private XmlNamespaceManager GetNamespace(XmlDocument document) 
{ 
   
XmlNamespaceManager mgr = new XmlNamespaceManager(document.NameTable); 
    mgr
.AddNamespace("ns0", "http://dev1/MyWebService1.wsdl"); 
   
return mgr; 
} 

You need to use the namespace manager because the XML document has namespaces associated with it, and XPath uses this in query resolution.

link|flag
That's close... Just tried it out and it's giving me an error: Namespace Manager or XsltContext needed. This query has a prefix, variable, or user-defined function. – Mat Nadrofsky Dec 17 '08 at 15:02
My bad - the SelectSingleNode should have a reference to the namespace manager with it. I'll update it. – Pete OHanlon Dec 17 '08 at 15:05
Thanks for the fix! :) I could just step-up my game and learn a few things and then you wouldn't have to solve my problems for me! ;) – Mat Nadrofsky Dec 17 '08 at 15:17

To solve this, I used Jon Skeet's answer. Here's the code that I had to implement to make this work (for anyone else's future benefit).

XmlDocument xmlDoc = new XmlDocument(); 
 
XNamespace ns0 = "http://dev1/MyWebService1.wsdl"; 
 
xmlDoc
.Load(request.GetResponse().GetResponseStream()); 
 
XDocument xDoc = XDocument.Load(new XmlNodeReader(xmlDoc));                           
 
String result = xDoc.Descendants(ns0 + "result").First().Value; 

This of course assumes I'm getting my response back from an HttpWebRequest named request.

link|flag

There are very good and complete answers to this question.

I'd add just out of curiosity, that an extremely simple XPath expression does the job in this particular case:

    normalize-space(/)

This is easily done in C# using something like the two lines below:

        XPathNavigator navigator = document.CreateNavigator(); 
 
       
string res = (string)navigator.Evaluate("normalize-space(/)"); 

With the good optimization of the .NET XPath engine, its evaluation may even be efficient.

link|flag

Your Answer

 
or
never shown

Not the answer you're looking for? Browse other questions tagged or ask your own question.