I have a response from web service in SOAP envelope as follows:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<ProcessTranResponse xmlns="http://www.polaris.co.uk/XRTEService/2009/03/">
<ProcessTranResult xmlns:a="http://schemas.datacontract.org/2004/07/XRTEService" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:PrintFormFileNameContents i:nil="true"/>
<a:ResponseXML>response_message</a:ResponseXML>
</ProcessTranResult>
</ProcessTranResponse>
</s:Body>
And I want to get response_message to a string variable. I tried doing
XDocument doc = XDocument.Parse(Response);
XNamespace xmlnsa = "http://schemas.datacontract.org/2004/07/XRTEService";
var ResponseXML = doc.Descendants(xmlnsa + "ResponseXML");
And when I use watch I see in ResponseXML -> Results View[0] -> Value my response_message, but I can't figure out what is the next step to get to Value from C#.
XContainer.Descendants returns a collection of elements. You should then try something like this:
foreach (XElement el in ResponseXML)
{
Console.WriteLine(el.Value);
}
Or you can do something like this if you know that there is always only one response:
XDocument doc = XDocument.Parse(Response);
XNamespace xmlnsa = "http://schemas.datacontract.org/2004/07/XRTEService";
XElement ResponseXML = (from xml in XMLDoc.Descendants(xmlnsa + "ResponseXML")
select xml).FirstOrDefault();
string ResponseAsString = ResponseXML.Value;
You can employ several solutions to meet your purpose while you may wanna introduce the structure of xml content or not.
Static attitude
You can simply use this:
XmlDocument _doc = new XmlDocument();
doc.LoadXml(_stream.ReadToEnd());
Then find the desired data with something like this:
doc.LastChild.FirstChild.FirstChild.LastChild.InnerText;
Read xml structure
You can write some additional lines of code to introduce namespaces and other xml contents to find/map the available data, by taking a look at extracting-data-from-a-complex-xml-with-linq
Related
I have an XML file which looks like this
<SendInvoiceResult xmlns="http://tempuri.org/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" IsSucceded="true">
<Value Id="123456" Number="1" InvoiceScenario="Scenario" />
</SendInvoiceResult>
I'm trying to read the attributes of this file but so far all my tries based on other questions on Stackoverflow either returned null or "Object reference not set to an instance of an object" error.
My latest try is this:
var testXml = new XmlDocument();
testXml.LoadXml(test);
var node = testXml.SelectSingleNode("/SendInvoiceResult/Value");
var id = node.Attributes["Id"].Value;
This approach returns "Object reference not set to an instance of an object" too. I'm wondering if something is wrong with the way XML is structures at this point.
I'm open to new methods and suggestions of course, all I need is to read the values of attributes in this and other similar XML files.
Use XDocument. It is much more modern and capable.
var doc = XElement.Load(test);
var id = doc.Root.Element("Value").Attribute("Id").Value;
You must define xml namespace.
var doc = new XmlDocument();
doc.Load("test.txt");
var manager = new XmlNamespaceManager(doc.NameTable);
manager.AddNamespace("ns", "http://tempuri.org/");
var node = doc.SelectSingleNode("/ns:SendInvoiceResult/ns:Value", manager);
var id = node.Attributes["Id"].Value;
Console.WriteLine(id);
Better use modern and more convenient linq to xml.
using System.Xml.Linq;
var doc = XDocument.Load("test.txt");
XNamespace ns = "http://tempuri.org/";
var id = doc.Root.Element(ns + "Value").Attribute("Id").Value;
Console.WriteLine(id);
Following is the XML from which I am trying to extract a child element.
<?xml version="1.0" encoding="UTF8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header xmlns="http://SomeValue/SomeValue/2009/01/SomeValue.xsd">
<Session>
<SessionId>SomeValue</SessionId>
<SequenceNumber>1</SequenceNumber>
<SecurityToken>SomeValue</SecurityToken>
</Session>
</soap:Header>
<soap:Body>
<Security_AuthenticateReply xmlns="http://SomeValue/SomeValue">
<processStatus>
<statusCode>P</statusCode>
</processStatus>
</Security_AuthenticateReply>
</soap:Body>
</soap:Envelope>
public static string AssignSecurityToken(string response)
{
string Token = "";
XNamespace ns = "http://schemas.xmlsoap.org/soap/envelope/";
XElement xdoc = XElement.Parse(response);
XElement root = xdoc.Descendants(ns + "Header").First();
Token = root.Element("Session").Element("SecurityToken").Value;
Token = root.Descendants("Session").Descendants().Where(n => n.Name == "SecurityToken").FirstOrDefault().Value;
return Token;
}
I want to extract the element Security Token.
Following are the things that I have already worked on:
Tried extracting the element using the approach suggested in the post
How to get value of child node from XDocument
Also posting some code for reference. Both the statements that are
assigning values to the Token variable are throwing "Object not set
to an instance of an object"exception.
Thanks in advance.
You need to take into account the Header's namepace.
public static string AssignSecurityToken(string response)
{
XNamespace ns1 = "http://schemas.xmlsoap.org/soap/envelope/";
XNamespace ns2 = "http://SomeValue/SomeValue/2009/01/SomeValue.xsd";
var envelope = XElement.Parse(response);
var header = envelope.Element(ns1 + "Header");
var session = header.Element(ns2 + "Session");
var security_token = session.Element(ns2 + "SecurityToken");
return security_token.Value;
}
Actually you could go ahead and just call
return XElement.Parse(response).Descendants()
.First(x => x.Name.LocalName == "SecurityToken").Value;
For this response only, it makes sense to just parse the string and extract an element.
This response uses two namespaces, one for SOAP headers and another for the Amadeus login response. You need the second one to retrieve the token :
//SOAP-only namespace
XNamespace soap = "http://schemas.xmlsoap.org/soap/envelope/";
//Default namespace
XNamespace ns = "http://SomeValue/SomeValue/2009/01/SomeValue.xsd";
var response=XElement.Parse(xml);
var token=response.Descendants(ns+"SecurityToken").First().Value;
Other Amadeus responses are huge and XDocument won't be much better (if at all) than using WCF and deserializing to strongly typed objects. XDocument deserializes the entire XML response, the same as DataContractSerializer. Instead of getting back a strongly-typed set of objects though, you get XElements you'll have to map to something else.
If you want to reduce memory consumption by only reading the parts you'll have to use XmlReader and read the XML tokens from the response stream one by one. That's a lot more work.
Another interesting thing is that Amadeus responses use multiple namespaces. This response uses just 2. Other responses, eg searches, use many more.
You might consider working with System.Xml.XmlDocument and System.Xml.XPath.XPathNavigator which are really easy to work with.
I wrote a simple example for you (supporting UTF-8 encoding):
System.Xml.XmlDocument someXmlFile = new System.Xml.XmlDocument();
string xmlPath= #"YOUR_XML_FULL_PATH";
string innerNodeToExtract= #"/Session/SecurityToken";
try
{
// Loading xml file with utf-8 encoding:
string xmlFileStr= Systm.IO.File.ReadAllText(xmlPath, System.Text.Encoding.UTF8);
// Creating the XPathNavigator:
System.Xml.XPath.XPathNavigator xmlNavigator= someXmlFile.CreateNavigator();
// Getting the inner value as string:
string value = xmlNavigator.SelectSingleNode(innerNodeToExtract).Value;
// some code...
}
catch(Exception)
{
// Handle failures
}
Please notice that you can also:
Extract inner values using "#" key.
Move to the child using xmlNavigator.MoveToNext().
And many other things that you can read here.
As I am a Beginner i Certainly need your Help.
I want to get a Specific Tag from Xdocument.
Following is the Content in the Xdocument:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<UcicLoginResponse xmlns="http://tempuri.org/">
<UcicLoginResult>
<Success>true</Success>
<authToken>xxxxxxx</authToken>
</UcicLoginResult>
</UcicLoginResponse>
</soap:Body>
</soap:Envelope>
Then I want to get the Value of the tag authToken.
Tried Lot with Descentants and Elements..But,due to the xml attributes,All tries leds to error.Anyone pls Help me...
Some of my tries Given:
XDocument _Xresult = XDocument.Parse(XmlResponse.Elements().Single().Value);
IEnumerable<XElement> xResponseItem = _Xresult.Descendants("UcicLoginResult");
if (xResponseItem.Descendants("Remarks").Any())
{
string sErr = _Xresult.Element("Remarks").Value;
throw new Exception("Authentication failed : " + sErr);
}
token = _Xresult.Descendants("authToken").FirstOrDefault().Value;
#
var root = XmlResponse.Root;
var res1= root.Elements("UcicLoginResult").Elements("authToken").FirstOrDefault().Value;
#
var resp=XmlResponse.Descendants("soap:Envelope").Descendants("soap:Body").Descendants("UcicLoginResponse").Descendants("UcicLoginResult").Elements("authToken");
#
IEnumerable<XElement> xResponseItem =XmlResponse.Descendants("UcicLoginResponse");
string sErr = xResponseItem.Descendants("UcicLoginResult").FirstOrDefault().Element("authToken").Value;
#
var res = XmlResponse.Descendants("soap:Envelope").Descendants("soap:Body").Descendants("UcicLoginResponse").Descendants("UcicLoginResult").Elements("authToken");
You are not specifying the namespace. http://tempuri.org/;
var xDocument = XDocument.Parse(xml);
XNamespace ns = "http://tempuri.org/";
var authToken = xDocument.Descendants(ns + "authToken").FirstOrDefault();
I don't know the xml where is it come from but it seems that you are communicating with a SOAP service and it could be better to get the data as object based by WCF client.
I have a service which returns the below xml as string.I am using Xdocument parse method and XmlDocument load methods to convert the string to xml. but i want to parse and get the status and i_numer which i need to use for further processing.can some one point me in right direction or give some hints.below is the xml i am using.
i tried the innerxml property from the Xdocument and XmlDocument which is returning the whole "" element and this is not what i needed.
<Report>
<Incidentreport Company="company1" ID="sample">
<status i_number="12345678" status="sucessful" />
</Incidentreport>
</Report>
The following should work:
string str = [string of xml goes here];
string i_number = string.Empty;
XmlDocument doc = new XmlDocument();
doc.Load(str);
XmlNode node = doc.SelectSingleNode("//status");
i_number = node.Attributes["i_number"].Value;
You can use SelectSingleNode() which accept XPath parameter to get the target attribute value in one go * :
var raw = #"<Report>
<Incidentreport Company='company1' ID='sample'>
<status i_number='12345678' status='sucessful' />
</Incidentreport>
</Report>";
var doc = new XmlDocument();
doc.LoadXml(raw);
var result = doc.SelectSingleNode("/Report/Incidentreport/status/#i_number");
Console.WriteLine(result.Value);
dotnetfiddle demo
*) notice how XML attribute can be referenced by using #attribute_name syntax in XPath
So I am trying to parse through some XML which is being returned from a REST API call. The XML looks like this (with many more <link>'s of course):
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<response status="Ok">
<links>
<link id="79380" hint="Some Text" linkDescription="This is the GET url for this Customer." link="/customer/79380" httpMethod="GET"/>
</links>
</response>
I am loading the XML file using the following code:
Stream resStream = response.GetResponseStream();
StreamReader reader = new StreamReader(resStream);
XElement doc = XElement.Load(reader);
I then loop through the elements like so:
IEnumerable<XElement> List =
from el in doc.Descendants("links") select el;
foreach (XElement e in List)
{
test += e.ToString();
}
It only loops through once and test is just a string that contains the entire XML file. My goal is to get the value of the "id" attribute from each element and place them in a list.
I have tried various things and I can't seem to get anything back but one huge string.
Try this:
var idList = doc.Descendants("link").Select(x => (int)x.Attribute("id"));