What is a good way to find a specific value in an

2019-04-07 22:53发布

问题:

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.)

回答1:

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.)



回答2:

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



回答3:

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.



回答4:

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.



回答5:

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.



回答6:

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.