Каков хороший способ найти определенное значение в XML-документе с помощью C#?
-
22-08-2019 - |
Вопрос
Я вызываю веб-службу, предоставляемую Oracle, которая принимает ввод ItemID и возвращает мне соответствующий номер элемента.Я хочу получить номер элемента, который был возвращен из 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 и т. д.)
Решение
Лично я бы использовал LINQ to XML, потому что считаю, что с ним проще иметь дело, чем с XPath, особенно когда речь идет о пространствах имен.Вы бы сделали что-то вроде:
XNamespace ns0 = "http://dev1/MyWebService1.wsdl";
String result = doc.Descendants(ns0 + "result").First().Value;
Обратите внимание, что doc
здесь ожидается XDocument
, нет а XmlDocument
.(Я предполагаю, что именно поэтому оно у вас не появилось.)
Другие советы
Кстати, вы можете обмануть проблему с пространством имен с помощью xpath следующим образом: //*[local-name()='result']
Если вы не хотите использовать 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 этого не делает.
С моей точки зрения, должно работать следующее:
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 использует их при разрешении запросов.
Чтобы решить эту проблему, я использовал ответ Джона Скита.Вот код, который мне пришлось реализовать, чтобы все заработало (для будущего блага всех остальных).
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 с именем запрос.
На этот вопрос есть очень хорошие и полные ответы.
Я бы добавил просто из любопытства, очень простое выражение XPath делает эту работу в данном конкретном случае:
normalize-space(/)
Это легко сделать на C#, используя что-то вроде двух строк ниже:
XPathNavigator navigator = document.CreateNavigator();
string res = (string)navigator.Evaluate("normalize-space(/)");
При хорошей оптимизации движка .NET XPath его оценка может быть даже эффективной.