How to read values from XML String from Web Service - c#

my source like this in C#:
string xml = null;
WebRequest req = WebRequest.Create("https://www.freegeoip.net/xml");
req.Credentials = CredentialCache.DefaultCredentials;
WebResponse res = req.GetResponse();
Stream dataStream = res.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
xml = reader.ReadToEnd();
reader.Close();
res.Close();
am getting response like this :
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<IP>162.158.50.10</IP> //IP address
<CountryCode>IN</CountryCode> //Country Code
<CountryName>India</CountryName>//Country Name
<RegionCode>MH</RegionCode> //Region Code
<RegionName>Maharashtra</RegionName>
<City>Mumbai</City>
<ZipCode></ZipCode>
<TimeZone>Asia/Kolkata</TimeZone>
<Latitude>18.975</Latitude>
<Longitude>72.8258</Longitude>
<MetroCode>0</MetroCode>
</Response>
/// XMl Reponse END///////////////////////////////
I want pass parameters to Database like :
objLogDetails.IPAddress = ???? //Here i want to pass IP :162.158.50.10 from XMl string

HEre are two methods, one using xpath and the other using linq 2 xml:
using System;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
namespace stackexchange
{
class Program
{
private static string theXml = #"<?xml version='1.0' encoding='UTF-8'?>
<Response>
<IP>162.158.50.10</IP> //IP address
<CountryCode>IN</CountryCode> //Country Code
<CountryName>India</CountryName>//Country Name
<RegionCode>MH</RegionCode> //Region Code
<RegionName>Maharashtra</RegionName>
<City>Mumbai</City>
<ZipCode></ZipCode>
<TimeZone>Asia/Kolkata</TimeZone>
<Latitude>18.975</Latitude>
<Longitude>72.8258</Longitude>
<MetroCode>0</MetroCode>
</Response>";
static void Main(string[] args)
{
XmlDocument xml = new XmlDocument();
xml.LoadXml(theXml);
XmlNode ip = xml.SelectSingleNode("/Response/IP");
Console.Out.WriteLine($"Ip Address: {ip.InnerText}");
XElement root = XElement.Parse(theXml);
XElement address = (from a in root.Descendants() where a.Name == "IP" select a).Single();
Console.Out.WriteLine($"Ip Address: {address.Value}");
}
}
}

What you can do here, is use an XElement to get items from the response and insert into your request.
You can do so like this:
//sets the node or remove
public static void SetOrRemoveNodeValue(XElement root, string xPath, string attributeName, string value)
{
XElement currentNode = root.XPathSelectElement(xPath);
if (currentNode != null)
{
if (currentNode.Attributes().FirstOrDefault(att => att.Name.LocalName.Equals(attributeName)) != null)
{
if (value == string.Empty)
{
currentNode.Attribute(attributeName).Remove();
}
else
{
currentNode.Attribute(attributeName).Value = value;
}
}
then use it like this:
Formatter.SetOrRemoveNodeValue("node", "your value type", "your value");
To extract value from the response, simply use:
currentNode.XPathSelectElement("//Response").Element("Ip").value;
Or simply
currentNode.XPathSelectElement("//Ip").value;

Trying This Code ..
private string mStrXMLStk = Application.StartupPath + "\\Path.xml";
private System.Xml.XmlDocument mXDoc = new XmlDocument();
mXDoc.Load(mStrXMLStk);
XmlNode XNode = mXDoc.SelectSingleNode("/Response");
if (XNode != null)
{
if (XNode != null)
{
int IntChildCount = XNode.ChildNodes.Count;
for (int IntI = 1; IntI <= 1; IntI++)
{
string LocalName = XNode.ChildNodes[IntI].LocalName;
XmlNode Node = mXDoc.SelectSingleNode("/Response/" + LocalName);
string _ip = Node.InnerText;
MessageBox.Show("IP" + _ip);
}
}
}
Completely worked

Related

Handling selectSingleNode(Xpath) in XML/Soap envelope having elements with same prefix and multiple uri

I have a Soap packet with same prefix ns2 for multiple uri: http://schemas.datacontract.org/2004/07/TestServices, http://schemas.datacontract.org/2004/07/TestServices.DTO.
When I am trying to set value in XDoc using xDoc.SelectSingleNode(xPath, oManager).InnerXml , it is giving null because of multiple uri conflict. Is there any way to dynamically hanlde this? I cannot do any changes in xpath as it is coming from different services with different format. My namespace manager code is as follows:
public static XmlNamespaceManager getAllNamespaces(XmlDocument xDoc)
{
XmlNamespaceManager result = new XmlNamespaceManager(xDoc.NameTable);
IDictionary<string, string> localNamespaces = null;
XPathNavigator xNav = xDoc.CreateNavigator();
while (xNav.MoveToFollowing(XPathNodeType.Element))
{
localNamespaces = xNav.GetNamespacesInScope(XmlNamespaceScope.Local);
foreach (var localNamespace in localNamespaces)
{
string prefix = localNamespace.Key;
if (string.IsNullOrEmpty(prefix))
prefix = "DEFAULT";
result.AddNamespace(prefix, localNamespace.Value);
}
}
return result;
}
foreach (Telerik.WinControls.UI.RadTreeNode tn in treeView.SelectedNode.Nodes)
{
if (tn.Text == r.Cells[0].Value.ToString())
{
string xPath = tn.FullPath;
xPath = "//" + xPath.Replace(#"\", "/").Replace(" ", "");
if (!(r.Cells[2].Value.ToString().StartsWith("<") && r.Cells[2].Value.ToString().EndsWith(">")) && !(r.Cells[2].Value.ToString().StartsWith("[") && r.Cells[2].Value.ToString().EndsWith("]")))
{
xDoc.SelectSingleNode(xPath, oManager).InnerXml = r.Cells[2].Value.ToString();
}
}
}
My soap envelope is as follows:
<s11:Envelope xmlns:s11='http://schemas.xmlsoap.org/soap/envelope/'>
<s11:Body>
<ns1:AccountCreation xmlns:ns1='www.test.com'>
<ns1:Data>
<ns2:LoginUser xmlns:ns2='http://schemas.datacontract.org/2004/07/TestServices'>?XXX?</ns2:LoginUser>
<ns2:UserPassword xmlns:ns2='http://schemas.datacontract.org/2004/07/TestServices'>?XXX?</ns2:UserPassword>
<ns2:IPAddress xmlns:ns2='http://schemas.datacontract.org/2004/07/TestServices'>?XXX?</ns2:IPAddress>
<ns2:ProductID xmlns:ns2='http://schemas.datacontract.org/2004/07/TestServices.DTO'>?999?</ns2:ProductID>
<ns2:BusinessAccountNumber xmlns:ns2='http://schemas.datacontract.org/2004/07/TestServices.DTO'>?999.99?</ns2:BusinessAccountNumber>
<ns2:StoreName xmlns:ns2='http://schemas.datacontract.org/2004/07/TestServices.DTO'>?XXX?</ns2:StoreName>
<ns2:Title xmlns:ns2='http://schemas.datacontract.org/2004/07/TestServices.DTO'>?XXX?</ns2:Title>
</ns1:Data>
</ns1:AccountCreation>
</s11:Body>
</s11:Envelope>

error - Data at the root level is invalid. Line 1, position 1

The articleabs webrequest method output’s id, when the POST request successful, which is forwarded createURL metod. However, I am getting the following error:
Error -> Data at the root level is invalid. Line 1, position 1.
Code line:
var document = XDocument.Parse(articleABS());
I have tried adding in a null statement condition to the createURL method, if the id from the article method is empty then exit the method, but that has not worked either and I am still getting the error.
public string createURL()
{
string uri = "";
var document = XDocument.Parse(articleABS());
var href = document.Descendants("link").Single().Attribute("title").Value;
href = href.Replace("Article", "");
string id = Regex.Match(href, #"\d+").Value;
var result = (#"#####" + id + "/sections");
return uri = result.ToString();
}
public string articleABS()
{
var result = (#"####" + mainID + "/articles");
string URL = result;
string method = "POST";
string postData = articleXML.createArticleABS();
try
{
if (hwrequest.Method == "POST")
{
....
}
using (HttpWebResponse hwresponse = (HttpWebResponse)hwrequest.GetResponse())
{
....
}
hwresponse.Close();
}
}
catch (WebException e)
{
.....
else
{
//
}
}
return responseData;
}
Example output of articleABS();
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="https://api.newsweaver.com/nwapistatic/ntsa-api.xsl" type="text/xsl"?>
<?xml-stylesheet href="https://api.newsweaver.com/nwapistatic/ntsa-api.css" type="text/css"?>
<status>
<code>409
</code>
<message>
content.article.required.title null
</message>
</status>
Please advise. Thank you

Is there any way to make my C# XMLManager work?

so I'm a total noob to C# is there any way to make this work?
It would also be a great help if someone could explain why my system doesn't work, and why another version would.
using System;
using System.Xml;
public class XMLManager
{
private XmlTextReader reader;
private XmlDocument document;
private XmlNodeList nodeList;
public void OpenFile(string file)
{
try
{
reader = new XmlTextReader(file);
reader.WhitespaceHandling = WhitespaceHandling.None;
reader.MoveToContent();
document = new XmlDocument();
document.Load(reader);
nodeList = document.SelectNodes(#"Settings/Settings");
}
catch (System.IO.FileNotFoundException)
{
}
}
public void CloseFile()
{
if (reader != null)
{
((IDisposable)reader).Dispose();
reader.Close();
reader = null;
}
document = null;
nodeList = null;
}
public string Get(string attrib)
{
for (int i = 0; i < nodeList.Count; i++)
{
reader.MoveToAttribute(i);
if (reader.Name == attrib)
{
return reader.Value;
}
}
return null;
}
}
Edit: Sorry for my bad formatting, this is my first time posting on Stack Overflow.
You are making multiple mistakes here.
First of all, you don't need a reader to read xml content into an XmlDocument.
Second, while trying to get the attributes, you are trying to proceed to the attributes using the reader which is obviously not having the context of the selected nodes.
Here is your updated XmlManager, but I have to note, there is a logical error too, which is, when the GetAttribute is invoked, you are searching all the Settings/Settings nodes and if find the attribute in any of them, return it. If the xml file contains only one Settings/Settings node, SelectSingleNode is better. I assume the following format:
<Settings>
<Settings attr1="attr1val" attr2="attr2val" />
</Settings>
Note: I also removed CloseFile method because it is no longer required.
public class XMLManager
{
private XmlDocument document;
private XmlNodeList nodeList;
public void OpenFile(string file)
{
document = new XmlDocument();
document.Load(file);
nodeList = document.SelectNodes(#"Settings/Settings");
}
public string Get(string attrib)
{
for (int i = 0; i < nodeList.Count; i++)
{
if (nodeList[i].Attributes[attrib] != null)
{
return nodeList[i].Attributes[attrib].Value;
}
}
return null;
}
}
Overall, you're doing way too much work.
If you have XML in a file, load it directly into an XML (DOM) object using XmlDocument.Load( strFileName );
To iterate all nodes matching an XPath query, see how I run through them.
try {
string strFileName = HttpContext.Current.Server.MapPath("\\data.xml");
XmlDocument xml = new XmlDocument();
xml.Load( strFileName );
foreach (XmlElement ndRow in xml.SelectNodes("//row")) {
string strTemp = ndRow.GetAttribute("foo");
}
} catch (Exception ex) {
Response.Write(ex.Message);
}

How do I differentiate types of XML files before deserializing?

I am loading MusicXML-files into my program. The problem: There are two “dialects”, timewise and partwise, which have different root-nodes (and a different structure):
<?xml version="1.0" encoding='UTF-8' standalone='no' ?>
<!DOCTYPE score-partwise PUBLIC "-//Recordare//DTD MusicXML 2.0 Partwise//EN" "http://www.musicxml.org/dtds/partwise.dtd">
<score-partwise version="2.0">
<work>...</work>
...
</score-partwise>
and
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE score-timewise PUBLIC "-//Recordare//DTD MusicXML 2.0 Timewise//EN" "http://www.musicxml.org/dtds/timewise.dtd">
<score-timewise version="2.0">
<work>...</work>
...
</score-timewise>
My code for deserializing the partwise score so far is:
using (var fileStream = new FileStream(openFileDialog.FileName, FileMode.Open))
{
var xmlSerializer = new XmlSerializer(typeof(ScorePartwise));
var result = (ScorePartwise)xmlSerializer.Deserialize(fileStream);
}
What would be the best way to differentiate between the two dialects?
Here's a way to do it by using an XDocument to parse the file, read the root element to determine the type, and read it into your serializer.
var xdoc = XDocument.Load(filePath);
Type type;
if (xdoc.Root.Name.LocalName == "score-partwise")
type = typeof(ScorePartwise);
else if (xdoc.Root.Name.LocalName == "score-timewise")
type = typeof(ScoreTimewise);
else
throw new Exception();
var xmlSerializer = new XmlSerializer(type);
var result = xmlSerializer.Deserialize(xdoc.CreateReader());
I would create both serializers
var partwiseSerializer = new XmlSerializer(typeof(ScorePartwise));
var timewiseSerializer = new XmlSerializer(typeof(ScoreTimewise));
Assuming that there is only these two I would call CanDeserialize method on one
using (var fileStream = new FileStream(openFileDialog.FileName, FileMode.Open))
{
using (var xmlReader = XmlReader.Create(filStream))
{
if (partwiseSerializer.CanDeserialize(xmlReader))
{
var result = partwiseSerializer.Deserialize(xmlReader);
}
else
{
var result = timewiseSerializer.Deserialize(xmlReader);
}
}
}
Obviously this is just an idea how to do it. If there were more options or according to your application design I would use a more sophisticated way to call CanDeserialize, but that method is the key in my opinion:
http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.candeserialize.aspx
The XmlReader class can be found here:
http://msdn.microsoft.com/en-us/library/System.Xml.XmlReader(v=vs.110).aspx
If you're concerned about resource usage:
internal const string NodeStart = "<Error ";
public static bool IsErrorDocument(string xml)
{
int headerLen = 1;
if (xml.StartsWith(Constants.XMLHEADER_UTF8))
{
headerLen += Constants.XMLHEADER_UTF8.Length;
}
else if (xml.StartsWith(Constants.XMLHEADER_UTF16))
{
headerLen += Constants.XMLHEADER_UTF16.Length;
}
else
{
return false;
}
if (xml.Length < headerLen + NodeStart.Length)
{
return false;
}
return xml.Substring(headerLen, NodeStart.Length) == NodeStart;
}
internal class Constants
{
public const string XMLHEADER_UTF16 = "<?xml version=\"1.0\" encoding=\"utf-16\"?>";
public const string XMLHEADER_UTF8 = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
}

While loop jumps unexpectedly while reading XML

I am reading an XML file using XMLDocument and XmlNodeReader.I do not know what happens to the while loop that it fails to run several parts of the code.
Here is my C# code:
public string TitleXml;
public string NameXml;
public string TypeXml;
public string ValueXml;
public Guid GuidXml;
public string DataString;
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml(MyParent.xmlstring);
XmlNodeReader xreader = new XmlNodeReader(xdoc);
while (xreader.Read())
{
switch (xreader.Name)
{
case"GUID":
GuidXml = Guid.Parse(xreader.ReadInnerXml());
//after this break the name of the xreader changes.
break;
case "Type":
TypeXml = xreader.ReadInnerXml();
break;
case "Name":
NameXml = xreader.ReadInnerXml();
break;
case "Title":
TitleXml = xreader.ReadInnerXml();
break;
}
}
xreader.Close();
}
Here is my XML:
<Item>
<GUID>9A4FA56F-EAA0-49AF-B7F0-8CA09EA39167</GUID>
<Type>button</Type>
<Title>Save</Title>
<Value>submit</Value>
<Name>btnsave</Name>
<MaxLen>5</MaxLen>
</Item>
It doesn't exactly answer your question, but an (at least according to me) easier way of solving this would be:
XDocument doc = XDocument.Load("test.xml");
string TitleXml = doc.Descendants("Title").Single().Value;
string NameXml = doc.Descendants("Name").Single().Value;
string TypeXml = doc.Descendants("Type").Single().Value;
string ValueXml = doc.Descendants("Value").Single().Value;
Guid GuidXml = Guid.Parse(doc.Descendants("GUID").Single().Value);
I also think you should use Linq-to-XML, but for your example I'd explicitly list the elements, like so (compilable example program):
using System;
using System.Xml.Linq;
namespace ConsoleApplication1
{
internal class Program
{
static void Main()
{
string xml =
#"<Item>
<GUID>9A4FA56F-EAA0-49AF-B7F0-8CA09EA39167</GUID>
<Type>button</Type>
<Title>Save</Title>
<Value>submit</Value>
<Name>btnsave</Name>
<MaxLen>5</MaxLen>
</Item>";
XElement elem = XElement.Parse(xml);
Guid GuidXml = Guid.Parse(elem.Element("GUID").Value);
Console.WriteLine(GuidXml);
string TypeXml = elem.Element("Type").Value;
Console.WriteLine(TypeXml);
string NameXml = elem.Element("Name").Value;
Console.WriteLine(NameXml);
string TitleXml = elem.Element("Title").Value;
Console.WriteLine(TitleXml);
}
}
}

Categories

Resources