Unable to get value from Descendants() or Element() using XML - c#

I can't seem to get a value from child nodes of an xml file. I feel like I have tried everything. All I want is to get the value of latitude and longitude of the location child node in the xml file. What am I doing wrong? Maybe I should try JSON instead of XML.
private void RequestCompleted(IAsyncResult result)
{
var request = (HttpWebRequest)result.AsyncState;
var response = (HttpWebResponse)request.EndGetResponse(result);
StreamReader stream = new StreamReader(response.GetResponseStream());
try
{
XDocument xdoc = XDocument.Load(stream);
XElement root = xdoc.Root;
XNamespace ns = xdoc.Root.Name.Namespace;
List<XElement> results = xdoc.Descendants(ns + "GeocodeResponse").Descendants(ns + "result").ToList();
List<XElement> locationElement = results.Descendants(ns + "geometry").Descendants(ns + "location").ToList();
List<XElement> lat = locationElement.Descendants(ns + "lat").ToList();
List<XElement> lng = locationElement.Descendants(ns + "lng").ToList();
}
catch (Exception ex)
{
MessageBox.Show("Error" + ex.Message)
}
}
xml
<GeocodeResponse>
<status>OK</status>
<result>
<type>street_address</type>
<formatted_address>134 Gearger Circle, Lexington, KY, USA</formatted_address>
<geometry>
<location>
<lat>36.31228546</lat>
<lng>-91.4444399</lng>
</location>
<location_type>ROOFTOP</location_type>
</geometry>
<place_id>ChIJtwDV05mW-IgRyJKZ7fjmYVc</place_id>
</result>
</GeocodeResponse>
Also here is a debug value that shows a count of zero. not sure what that means. I just need the value of lat and lng.

If I understand your question correctly you are looking for the list of all the lat and lng in the XML Document.
XDocument xdc = XDocument.Load(stream);
var AllLats = xdc.Descendants("lat");
var AllLong = xdc.Descendants("lng");
You wont need to drill down to the hierarchy to get the XML Nodes value with Descendants
Another part is ns that is your namespace has to be included for the XML which looks like
<SOmeNS:address_component>
not for the elements which does have name without :
attaching the screenshot to see if you want this output.

Your code works correctly, make sure your xml loaded in the line using debugger.
XDocument xdoc = XDocument.Load(stream);
And check namespace, when executing your code i got empty string in ns or try removing the ns from your code.
XNamespace ns = xdoc.Root.Name.Namespace;
To get the lat and long use below code.
List<XElement> lat = locationElement.Descendants(ns + "lat").ToList();
List<XElement> lng = locationElement.Descendants(ns + "lng").ToList();
var latitudeval = lat[0].value;
var longitudeval = lng[0].value;

Get the element you are interested in by name. Then get the first and last child node since the first child is lat and the last child is long.
var sw = doc.Descendants("location");
var lat = sw.Descendants().First();
var lng = sw.Descendants().Last();

//XNamespace ns = xdoc.Root.Name.Namespace;
XNamespace ns = xdoc.GetDefaultNamespace();

The only way I was able to fix my issue was to send a request for JSON instead of XML. Then using Regex I was able to remove the <string> portion of the response. This worked perfectly and JSON is easier to work with in my opinion anyways.
private void RequestCompleted(IAsyncResult result)
{
var request = (HttpWebRequest)result.AsyncState;
var response = (HttpWebResponse)request.EndGetResponse(result);
JObject jdoc = null;
Stream stream = response.GetResponseStream();
try
{
StreamReader reader = new StreamReader(stream);
string text = reader.ReadToEnd();
Regex rgx = new Regex("<.*\\>");
string newResult = rgx.Replace(text, "");
JObject json = JObject.Parse(newResult);
jdoc = json;
JArray results = (JArray)json["results"];
if (results.Count == 0)
{
}
else
{
foreach(JObject obj in results)
{
string formattedAddress = (string)obj["formatted_address"];
double lat = (double)obj["geometry"]["location"]["lat"];
double lng = (double)obj["geometry"]["location"]["lng"];
}
}
}
catch (Exception ex)
{
MessageBox.Show("Error" + ex.Message);
}
}

Related

String.Replace not replacing

I'm doing some file clean up in an xml file and trying to use string.Replace to replace certain text blocks but it does not seem to be replacing the text that I am searching on.
My clean up code is follows
private Stream PrepareFile(string path)
{
string data = File.ReadAllText(path);
var newData = data.Replace("<a:FMax xmlns:b=\"http://www.w3.org/2001/XMLSchema\" i:type=\"b:string\"/>", "<a:FMax>0</a:FMax>")
.Replace("<a:KVy xmlns:b=\"http://www.w3.org/2001/XMLSchema\" i:type=\"b:string\"/>", "<a:KVy>0</a:KVy>")
.Replace("<a:Td xmlns:b=\"http://www.w3.org/2001/XMLSchema\" i:type=\"b:string\"/>", "<a:Td>0</a:Td>")
.Replace("<a:VyLim xmlns:b=\"http://www.w3.org/2001/XMLSchema\" i:type=\"b:string\"/>", "<a:VyLim>0</a:VyLim>");
var newData2 = newData.Replace("<a:VxTableSxI3_2I xmlns:b=\"http://www.w3.org/2001/XMLSchema\" i:type=\"b:string\"/>", "<a:VxTableSxI3_2I>0</a:VxTableSxI3_2I>");
byte[] bytes = Encoding.ASCII.GetBytes(newData2);
return new MemoryStream(bytes);
}
I should be able to write back to the original 'data' variable, but I split the variables out to be able to compare the strings before and after the replace. My xml file contains the following values(copied verbatim)
<a:LongitudinalTracker z:Id="i58">
<Name xmlns="http://schemas.datacontract.org/2004/07/HmsSim.EntityModule.BaseTypes" i:nil="true"/>
<a:FMax xmlns:b="http://www.w3.org/2001/XMLSchema" i:type="b:string"/>
<a:K>2</a:K>
<a:KVy xmlns:b="http://www.w3.org/2001/XMLSchema" i:type="b:string"/>
<a:Td xmlns:b="http://www.w3.org/2001/XMLSchema" i:type="b:string"/>
<a:VyLim xmlns:b="http://www.w3.org/2001/XMLSchema" i:type="b:string"/>
</a:LongitudinalTracker>
And the before and after strings look identical. I'm sure I am missing something silly, but I can't see what it is. Most of the answers to similar questions point out that the original code is not using the return value, but in this case I am definitely using the return value.
As suggested I am posting the code that ended up solving this.
private Stream PrepareFile(string path)
{
string data = File.ReadAllText(path);
var xml = XDocument.Parse(data);
XNamespace ns = "http://schemas.datacontract.org/2004/07/HmsSim.EntityModule.Entities.SimulationEntities.Track";
var longTracker = from item in xml.Descendants(ns + "LongitudinalTracker") select item;
foreach (var xElement in longTracker.Elements())
{
XNamespace nsI = "http://www.w3.org/2001/XMLSchema-instance";
if (xElement.Attribute(nsI + "type") != null)
{
xElement.Attribute(nsI + "type").Remove();
XAttribute attribute = new XAttribute(nsI + "nil", "true");
xElement.Add(attribute);
}
}
var latTracker = from item in xml.Descendants(ns + "LateralTracker") select item;
foreach (var xElement in latTracker.Elements())
{
XNamespace nsI = "http://www.w3.org/2001/XMLSchema-instance";
if (xElement.Attribute(nsI + "type") != null)
{
xElement.Attribute(nsI + "type").Remove();
XAttribute attribute = new XAttribute(nsI + "nil", "true");
xElement.Add(attribute);
}
}
Stream stream = new MemoryStream();
xml.Save(stream);
// Rewind the stream ready to read from it elsewhere
stream.Position = 0;
return stream;
}
This code works and is less brittle than the original code. As always, suggestions are welcome. Thanks to everyone who commented and led me towards this answer, I appreciate it.

Read XML File Using Linq is not reading element

I am not able to get the value from this xml response, I will appreciate any help.
<Response>
<Result>
<Item1>GREEN</Item1>
<Item2>05/19/2017 22:08:14</Item2>
</Result>
<Other>
<Id>xxxxxxxxxxxxc</Id>
</Other>
</Response>
What I tried so far but the results is empty
string responseXml = response.ToXML();
XElement doc = XElement.Load(new StringReader(responseXml));
var results = from p in
doc.Descendants("Result")
select new
{
item = p.Element("Item1").Value,
};
foreach (var elm in results)
{
Console.WriteLine(elm.item);
}
Use Parse instead of load. You may also be getting error due to extra characters in the string. In the string you postged there are single quotes. Not sure if the single quote is in the actual string you are using.
string responseXml = "<Response>" +
"<Result>" +
"<Item1>GREEN</Item1>" +
"<Item2>05/19/2017 22:08:14</Item2>" +
"</Result>" +
"<Other>" +
"<Id>xxxxxxxxxxxxc</Id>" +
"</Other>" +
"</Response>";
XElement doc = XElement.Parse(responseXml);
var results = from p in
doc.Descendants("Result")
select new
{
item = p.Element("Item1").Value,
};
foreach (var elm in results)
{
Console.WriteLine(elm.item);
}

Get specific xml lines with linq

I have an XML looking like this:
<data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<row>
<Alert>warning</Alert>
</row>
</data>
I wan't to get all the rows. In this case, the value that I wan't is "Alert".
This is as fare as I've got...
using (XmlReader reader = cmd.ExecuteXmlReader())
{
string xmlFile = "";
while (reader.Read())
{
xmlFile = reader.ReadOuterXml();
}
var xmlElement = XElement.Parse(xmlFile);
var result = xmlElement.Elements("data").Where(x => x.Value.Equals("row")).ToList();
}
I know something is wrong with my linq, but I'm quite new to linq and would like some help.
Thanks!
XNamespace ns = "http://www.w3.org/2001/XMLSchema-instance";
var xDocument = XDocument.Load("path");
var result = xDocument.Descendants(ns + "row").ToList();
I hope this will work. Please try this.
var xDocument = XDocument.Load(#"XmlFilePath");
//Use below if you have xml in string format
// var xDocument = XDocument.Parse("XmlString");
XNamespace ns = xDocument.Root.GetDefaultNamespace();
var result = xDocument.Descendants(ns + "row").ToList();

How to read xml file c#

<CPT xmlns="http://www.example.org/genericClientProfile" xmlns:ns2="http://www.blahblah.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.org/genericClientProfile genericClientProfile.xsd">
<header>
<serviceId>CPT-UK</serviceId>
<versionId>1.0</versionId>
<brandCode>CUK</brandCode>
<creationTime>2013-09-26T13:55:32.31+02:00</creationTime>
</header>
</CPT>
I need to be able to read the elements in the header tag. I'm struggling to read the values for some reason, which i'm not sure of. What i've tried:
public ActionResult readxmldata()
{
using (var db = new CPTEntities())
{
var file = System.IO.Directory.GetFiles("C:\\Workspace\\CPTStaging","*.xml");
foreach (var xmldoc in file)
{
XmlDocument docpath = new XmlDocument();
docpath.Load(xmldoc);
CPTPROFILE doc = new CPTPROFILE();
db.SaveChanges();
H_HEADER header = new H_HEADER();
header.SERVICEID = docpath.SelectSingleNode("//CPT/header/#serviceId").Value;
header.VERSIONID = Convert.ToDecimal(docpath.SelectSingleNode("//CPT/header/#versionId").Value);
header.CREATIONTIME = Convert.ToDateTime(docpath.SelectSingleNode("//CPT/header/#creationTime").Value);
header.BRANDCODE = docpath.SelectSingleNode("//CPT/header/#brandCode").Value;
db.CPTPROFILEs.AddObject(doc);
db.SaveChanges();
}
}
Your XML uses namespaces. xmlns attribute declares default namespace. You should use it for each element of the XML.
XNamespace ns = "http://www.example.org/genericClientProfile";
XDocument doc = XDocument.Load(xmldoc);
XElement header = doc.Root.Element(ns + "header");
For comparison, here is one way to do it with Linq-to-XML:
XDocument doc = XDocument.Load(xmlFileName);
XNamespace ns = "http://www.example.org/genericClientProfile";
var header = doc.Descendants(ns+"header").Single();
H_HEADER header = new H_HEADER();
header.SERVICEID = (string) header.Element(ns + "serviceId");
header.VERSIONID = (double) header.Element(ns + "versionId");
header.BRANDCODE = (string) header.Element(ns + "brandCode");
header.CREATIONTIME = (DateTime) header.Element(ns + "creationTime");

Using C# and XDocument/XElement to parse a Soap Response

Here is a sample soap response from my SuperDuperService:
<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>
<MyResponse xmlns="http://mycrazyservice.com/SuperDuperService">
<Result>32347</Result>
</MyResponse>
</soap:Body>
</soap:Envelope>
For some reason when I try to grab the Descendant or Element of "Result" I get null. Does it have something to do with the Namespace? Can someone provide a solution to retrieve Result from this?
You might want to try something like this:
string myNamespace= "http://mycrazyservice.com/SuperDuperService";
var results = from result in yourXml.Descendants(XName.Get("MyResponse", myNamespace))
select result.Element("Result").value
Don't have VS on this laptop so I can't double check my code, but it should point you in the right direction using LINQ to SQL.
to extend Justin's answer with tested code with a return that excpects a boolean and that the response and result start with the method name (BTW - a surprise is even thought the XML element does not show the NS it requires it when parsing):
private string ParseXml(string sXml, string sNs, string sMethod, out bool br)
{
br = false;
string sr = "";
try
{
XDocument xd = XDocument.Parse(sXml);
if (xd.Root != null)
{
XNamespace xmlns = sNs;
var results = from result in xd.Descendants(xmlns + sMethod + "Response")
let xElement = result.Element(xmlns + sMethod + "Result")
where xElement != null
select xElement.Value;
foreach (var item in results)
sr = item;
br = (sr.Equals("true"));
return sr;
}
return "Invalid XML " + Environment.NewLine + sXml;
}
catch (Exception ex)
{
return "Invalid XML " + Environment.NewLine + ex.Message + Environment.NewLine + sXml;
}
}
Maybe like this:
IEnumerable<XElement> list = doc.Document.Descendants("Result");
if (list.Count() > 0)
{
// do stuff
}
You're searching in the right direction, it definitely has to do with the namespace.
The code below returns the first element found for the combination of namespace and element name.
XDocument doc = XDocument.Load(#"c:\temp\file.xml");
XNamespace ns = #"http://mycrazyservice.com/SuperDuperService";
XElement el = doc.Elements().DescendantsAndSelf().FirstOrDefault( e => e.Name == ns + "Result");
You can try with this.
Regex regex = new Regex("<Result>(.*)</Result>");
var v = regex.Match(yourResponse);
string s = v.Groups[1].ToString();

Categories