Что такое хороший способ найти конкретное значение в документе XML с помощью C #? - PullRequest
6 голосов
/ 17 декабря 2008

Я вызываю WebService, предоставляемый Oracle, который принимает ввод ItemID и возвращает мне соответствующий номер Item. Я хочу получить номер товара, который был возвращен из XML, содержащегося в ответе.

XML выглядит так:

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

Мне интересно захватить только <ns0:result>1010603</ns0:result>, в особенности только 1010603.

Я не проделал много работы по синтаксическому анализу XML с использованием C #, и я до сих пор играю с несколькими различными методами. Каков рекомендуемый способ сделать это?

Я на VS2008 (поэтому XPath доступен и т. Д.)

Ответы [ 6 ]

15 голосов
/ 17 декабря 2008

Я бы лично использовал LINQ to XML, потому что мне проще с ним обращаться, чем с XPath, особенно когда речь идет о пространствах имен. Вы бы сделали что-то вроде:

XNamespace ns0 = "http://dev1/MyWebService1.wsdl";

String result = doc.Descendants(ns0 + "result").First().Value;

Обратите внимание, что здесь doc ожидается как XDocument, , а не и XmlDocument. (Я думаю, именно поэтому он не показывался для вас.)

5 голосов
/ 17 декабря 2008

Между прочим, вы можете обмануть проблему пространства имен с помощью xpath: //*[local-name()='result']

3 голосов
/ 17 декабря 2008

Если вы не хотите использовать Linq, вы можете использовать XPathDocument для получения значения:

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 занимает меньше памяти и, скорее всего, быстрее в вашем сценарии, чем XmlDocument. XmlDocument создает полную объектную модель вашего XML-документа в памяти, тогда как XPathDocument этого не делает.

2 голосов
/ 17 декабря 2008

С макушки головы должно работать следующее:

XmlDocument doc = new XmlDocument();
doc.PreserveWhitespace = true;

XmlNamespaceManager mgr = GetNamespace(doc);
doc.LoadXml(xmltext);

XmlNode nd = doc.DocumentElement.SelectSingleNode("//ns0:result", mgr);

Код пространства имен выглядит следующим образом:

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

Вам необходимо использовать диспетчер пространства имен, поскольку с документом XML связаны пространства имен, и XPath использует это в разрешении запроса.

1 голос
/ 17 декабря 2008

Чтобы решить эту проблему, я использовал ответ Джона Скита. Вот код, который мне пришлось реализовать, чтобы сделать эту работу (для чьей-либо будущей выгоды).

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;

Это, конечно, предполагает, что я получаю ответ от HttpWebRequest с именем request .

0 голосов
/ 17 декабря 2008

Есть очень хорошие и полные ответы на этот вопрос.

Я бы добавил просто из любопытства, что чрезвычайно простое выражение XPath делает работу в данном конкретном случае:

normalize-space(/)

Это легко сделать в C #, используя что-то вроде двух строк ниже:

        XPathNavigator navigator = document.CreateNavigator();

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

При хорошей оптимизации механизма .NET XPath его оценка может быть даже эффективной.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...