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.)
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.)
fwiw you can cheat the namespace issue with an xpath like this: //*[local-name()='result']
If you don't want to go for Linq you could use XPathDocument to retrieve the value:
XPathDocument xmldoc = new XPathDocument(@"C:\tmp\sample.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.
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.
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.
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.
来源:https://stackoverflow.com/questions/374734/what-is-a-good-way-to-find-a-specific-value-in-an-xml-document-using-c