Creating an xml parsing function in C# - c#

I have an XML that's obtained from a web service, i'm using an HttpClient for it. This is what the XML looks like:
<respuesta>
<entrada>
<rut>7059099</rut>
<dv>9</dv>
</entrada>
<status>
<code>OK</code>
<descrip>Persona tiene ficha, ok</descrip>
</status>
<ficha>
<folio>3204525</folio>
<ptje>7714</ptje>
<fec_aplic>20080714</fec_aplic>
<num_integ>2</num_integ>
<comuna>08205</comuna>
<parentesco>1</parentesco>
<fec_puntaje>20070101</fec_puntaje>
<personas>
<persona>
<run>7059099</run>
<dv>9</dv>
<nombres>JOSE SANTOS</nombres>
<ape1>ONATE</ape1>
<ape2>FERNANDEZ</ape2>
<fec_nac>19521101</fec_nac>
<sexo>M</sexo>
<parentesco>1</parentesco>
</persona>
<persona>
<run>8353907</run>
<dv>0</dv>
<nombres>JUANA DEL TRANSITO</nombres>
<ape1>MEDINA</ape1>
<ape2>ROA</ape2>
<fec_nac>19560815</fec_nac>
<sexo>F</sexo>
<parentesco>2</parentesco>
</persona>
</personas>
</ficha>
I'm trying to make a function that can parse this and, right now (just for the purpose of testing my understanding of the language since i'm new to it) i just need it to find the VALUE inside an "rut" tag, the first one, or something like that. More precisely I need to find a value inside the XML and return it, so i can show it on a label that's on my .aspx page. The code of my parsing function looks like this:
public static String parseXml(String xmlStr, String tag)
{
String valor;
using (XmlReader r = XmlReader.Create(new StringReader(xmlStr)))
{
try
{
r.ReadToFollowing(tag);
r.MoveToContent();
valor = r.Value;
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex.InnerException);
}
}
return valor;
}
This code is based on an example I found on youtube made by the guys from microsoft where they "explain" how to use the parser.
Also, this function is being called from inside one of the tasks of the HttpClient, this is it:
protected void rutBTN_Click(object sender, EventArgs e)
{
if (rutTB.Text != "")
{
HttpClient client = new HttpClient();
String xmlString = "";
String text = "";
var byteArray = Encoding.ASCII.GetBytes("*******:*******"); //WebService's server authentication
client.BaseAddress = new Uri("http://wschsol.mideplan.cl");
var par = "mod_perl/xml/fps-by-rut?rut=" + rutTB.Text;
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
client.GetAsync(par).ContinueWith(
(requestTask) =>
{
HttpResponseMessage resp = requestTask.Result;
try
{
resp.EnsureSuccessStatusCode();
XmlDocument xmlResp = new XmlDocument();
requestTask.Result.Content.ReadAsStreamAsync().ContinueWith(
(streamTask) =>
{
xmlResp.Load(streamTask.Result);
text = xmlResp.InnerXml.ToString();
xmlString = parseXml(text, "rut"); //HERE I'm calling the parsing function, and i'm passing the whole innerXml to it, and the string "rut", so it searches for this tag.
Console.WriteLine("BP");
}).Wait();
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex.InnerException);
}
}).Wait();
testLBL.Text = xmlString; //Finally THIS is the label i want to show the "rut" tag's value to be shown.
testLBL.Visible = true;
}
else
{
testLBL.Text = "You must enter an RUT number";
testLBL.Visible = true;
}
}
The problem is that when i put some breakpoints into the parsing function i can see that it's receiving correctly the innerxml string (as a string) but it's not finding the tag called "rut", or rather not finding anything at all, since it's returning an empty string ("").
I know that maybe this is not the correct way to parse an xmlDocument, so if someone can help me out i'd be really really thankful.
EDIT:
Ok, so i won't ask for any tutorial or such (I requested that to avoid asking noob questions). But anyway, please, instead of just answering "you better do it like this", I'd appreciate if you could explain me things like "THIS is what you're doing wrong and THAT'S why your code isn't working", and THEN tell me how you guys would do it instead.
Thanks in advance!

As you only want to retrieve a single field value I would recommend using Xpath.
Basically you create a XpathNavigator from a XpathDocument or xmlDocument and then use Select to get the content of the rut node:
XPathNavigator navigator = xmlResp.CreateNavigator();
XPathNodeIterator rutNode = navigator.SelectSingleNode("/respuesta/entrada/rut");
string rut = rutNode.Value

Related

How can I determine the class of an XML serialized object in C# before I deserialize it?

I have a server that accepts requests as XML serialized objects which could be any of 10 or so different Classes. Of course in order for the server to process the request, it must first de-serialize the XML string back into an object. To do that, it needs to know what class the object came from to choose the correct de-serializer and re-construct the object. So it would be good to be able to just quickly inspect the XML string before attempting to de-serialize it to get the object type and then select the appropriate de-serializer.
I have been using the following code, but, like the song goes, "I know there's got to be a better way..." Any suggestions or insight would be appreciated.
private void button1_Click(object sender, EventArgs e)
{
//any class - does not matter - create an object
SomeClass tc = new SomeClass();
//populate it
tc.i = 5;
tc.s = "Hello World";
tc.d = 123.456;
//Serialize it to XML
StringWriter xml = new StringWriter();
System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(typeof(SomeClass));
x.Serialize(xml, tc);
//Extract the Class name and show the XML to the user without de-serializing it
textBox1.Text = GetClassNameFromXMLSerializedString(xml.ToString());
}
private string GetClassNameFromXMLSerializedString(string xml)
{
//The class name is somewhere in the xml
string classname = xml;
//get the start of class name
classname = xml.Substring(classname.IndexOf('>') + 4);
//get the class name which is terminated by a space
classname = classname.Substring(0, classname.IndexOf(' '));
//return it
return classname;
}
The XML Deserializer does not need to know what type it is before deserializing. The MSDN Article about the Deserialize method has some useful information about it and of course it has a code snippet, which I've put below.
I think you might have confused yourself with the fact that the server will deserialize it to an object, but then won't know what to do with it. You can always do a switch case for the result of the ReturnedObject.GetType() method and work out what you need to do with it.
You can just serialize it to an object like this:
var ReturnedObject = XMLSerializer.Deserialize(reader);
Then you can go ahead and do
switch (ReturnedObject.getType())
{
case MyClass:
// Insert code here
case AnotehrClass:
//Do something else here for another class
}
If you really want to you can read the 3rd element like this:
using (XmlReader xr = XmlReader.Create(GenerateStreamFromString(xml.ToString())))
{
xr.Read();
xr.Read();
xr.Read();
textBox1.Text = xr.Name;
}
Using this helper function:
public static MemoryStream GenerateStreamFromString(string value)
{
return new MemoryStream(Encoding.Unicode.GetBytes(value ?? ""));
}
All checks omitted..
If you want to you can test if the 1st element is xml and the 2nd one is empty.
I'm not really sure if this is a good idea.
XDocument xd = XDocument.Parse(xml.ToString()); switch (xd.Root.Name.ToString()) { case "Class1": //do something break; case "Class2": //do something break; }

C# Extracting data from Json or DataSets - Porting from Python (Json to Dict)

I have the following Python script which I need to port to C#. This gets a JSON response from a URL and then pops it into a dictionary. Then it checks for the data next_page and if there is data (it's not empty) it then returns true. Underneath I'll paste the C# code I have but I'm really struggling to do the final part. I don't know and I certainly don't want to understand the data in the JSON response, I just want to know if the field next_page is there.
# Gets JSON response
response = requests.get(url, auth=(user, pwd))
if response.status_code != 200:
print('Status:', response.status_code, 'Problem with the request. Exiting.')
exit()
data = response.json()
if(data['next_page']):
return True
else:
return False
So this is the c# code I've got:
using Newtonsoft.Json;
string response = "";
using (WebClient client = new WebClient())
{
client.UseDefaultCredentials = true;
client.Credentials = new NetworkCredential(user, password);
try
{
response = client.DownloadString(url);
} catch (Exception e)
{
throw e;
}
}
XmlDocument xml = JsonConvert.DeserializeXmlNode(json, "RootObject");
XmlReader xr = new XmlNodeReader(xml);
DataSet ds = new DataSet("Json Data");
ds.ReadXml(xr);
From what I've seen on the web DataSets work best when you know what the data inside of it is. I just want to know if there is a field called next_page and if there is, is it empty or does it have data. I'm just struggling to get anything out of the DataSet.
You will want to include the JSON.net nuget package (http://james.newtonking.com/json) this lets you deserialize the JSON response into a dictionary (or preferably a new class) allowing you to access the response.
eg add this into your try catch after including the library
var dict = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, string>>(response);
Alternativly you could create a new class that represents the expected JSON and deserialize into that
public class ResponseObject
{
public string next_page { get; set; }
}
var responseResult = Newtonsoft.Json.JsonConvert.DeserializeObject<ResponseObject>(response);

How to convert XMLDocument type to string in order to show the result in a label

I'm trying to show weather information on my website from world weather online. I'm using VS2012 with c# to create this.
I could able to retrieve data from world weather online to a function under a XMLDocument type variable "WP_XMLdoc".
Take a look at the code below:
public static XmlDocument WeatherAPI(string sLocation)
{
HttpWebRequest WP_Request;
HttpWebResponse WP_Response = null;
XmlDocument WP_XMLdoc = null;
String Value;
string sKey = "xxxxxxxxxxxxxxxxxxxxxxxxx"; //The API key generated by World Weather Online
string sRequestUrl = "http://api.worldweatheronline.com/free/v1/weather.ashx?format=xml&"; //The request URL for XML format
try
{
//Here we are concatenating the parameters
WP_Request = (HttpWebRequest)WebRequest.Create(string.Format(sRequestUrl + "q=" + sLocation + "&key=" + sKey));
WP_Request.UserAgent = #"Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.4) Gecko/20070515 Firefox/2.0.0.4";
//Making the request
WP_Response = (HttpWebResponse)WP_Request.GetResponse();
WP_XMLdoc = new XmlDocument();
//Assigning the response to our XML object
WP_XMLdoc.Load(WP_Response.GetResponseStream());
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
WP_Response.Close();
return WP_XMLdoc;
}
}
So, now I just want to take XML data from "WP_XMLdoc" variable and show few details like temp_c, windspeed, time etc in my labels.
How can I do that?
The XML data that rest under "WP_XMLdoc" is given below:
<?xml version="1.0" encoding="UTF-8"?>
<data>
<request>
<type>City</type>
<query>London, United Kingdom</query>
</request>
<current_condition>
<observation_time>04:17 AM</observation_time>
<temp_C>17</temp_C>
<temp_F>63</temp_F>
<weatherCode>143</weatherCode>
<weatherIconUrl>
<![CDATA[http://cdn.worldweatheronline.net/images/wsymbols01_png_64/wsymbol_0006_mist.png]]>
</weatherIconUrl>
<weatherDesc>
<![CDATA[Mist]]>
</weatherDesc>
<windspeedMiles>0</windspeedMiles>
<windspeedKmph>0</windspeedKmph>
<winddirDegree>62</winddirDegree>
<winddir16Point>ENE</winddir16Point>
<precipMM>0.0</precipMM>
<humidity>94</humidity>
<visibility>2</visibility>
<pressure>1010</pressure>
<cloudcover>50</cloudcover>
</current_condition>
<weather>
<date>2014-09-19</date>
<tempMaxC>28</tempMaxC>
<tempMaxF>82</tempMaxF>
<tempMinC>14</tempMinC>
<tempMinF>57</tempMinF>
<windspeedMiles>5</windspeedMiles>
<windspeedKmph>8</windspeedKmph>
<winddirection>SSE</winddirection>
<winddir16Point>SSE</winddir16Point>
<winddirDegree>149</winddirDegree>
<weatherCode>356</weatherCode>
<weatherIconUrl>
<![CDATA[http://cdn.worldweatheronline.net/images/wsymbols01_png_64/wsymbol_0010_heavy_rain_showers.png]]>
</weatherIconUrl>
<weatherDesc>
<![CDATA[Moderate or heavy rain shower]]>
</weatherDesc>
<precipMM>8.3</precipMM>
</weather>
</data>
Please help!
Assuming that your existing code successfully load the XML data to XmlDocument object, we can then use SelectSingleNode() passing suitable XPath expression as argument to get any particular part of the XML document. For example, to get <temp_C> value :
string temp_c = WP_XMLdoc.SelectSingleNode("/data/current_condition/temp_C")
.InnerText;
Another option is using newer XML API, XDocument. It has Load() method which functionality is similar to XmlDocument.Load() :
XDocument WP_XMLdoc = XDocument.Load(WP_Response.GetResponseStream());
Using this approach, we can simply cast XElement to string to get it's value :
string temp_c = (string)WP_XMLdoc.XPathSelectElement("/data/current_condition/temp_C");
Try something like this, as an example:
var str = #"<your xml here>";
XDocument xdoc = XDocument.Parse(str);
var output = new List<string>();
foreach (var element in xdoc.Element("data").Element("current_condition").Elements())
{
output.Add(string.Format("{0} : {1}",element.Name, element.Value.ToString()));
}
This would traverse the properties of the current_condition node, you can adjust as necessary to extract what you need.
Ok, according to your answer in comments I believe you need to show multiple columns of data.
Best option would be to use a GridView to populate your XML data using ADO.net. It's bit easy.
Have a look at this SO thread

Parsing a website data c# - HTML agility pack

I tried to parse the results from this website.
http://www.nokia.com/in-en/store-locator/?action=storeSearch&qt=madurai&tags=Nokia_Recycling_Point&country=IN
I need specifically the contents of the div class 'result-wrapper'. That is, all the 'h4', 'category' and 'description' span classes. The following is the code I could reach upto, later on, I do not know to parse that particular div. I need help to get all the contents of that div class.
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
string htmlPage = "";
using (var client = new HttpClient())
{
try
{
htmlPage = await client.GetStringAsync("http://www.nokia.com/in-en/store-locator/?action=storeSearch&qt=madurai&tags=Nokia_Recycling_Point&country=IN");
}
catch (HttpRequestException exc) { }
}
HtmlDocument htmlDocument = new HtmlDocument();
htmlDocument.LoadHtml(htmlPage);
Well, you can try:
var resultWrapperDivs = htmlDocument.DocumentNode.SelectNodes("//div[#class='result-wrapper']");
foreach (var resultWrapperDiv in resultWrapperDivs)
{
// Do stuff with each div.
}
Also, to get a specific content/"html tag" you can take each resultWrapperDiv alone and get also its children nodes (resultWrapperDiv.SelectSingleNode or resultWrapperDiv.SelectNodes)

code contracts usage with exceptions

void ReadContent(string path)
{
Contract.Requires(path!=null);
string contentofileasstring = filehelperobj.GetContent(path);
if(String.IsNullOrEmpty(contentofileasstring ))
{
throw new FileContentException(path + "No content found");
}
m_xmlobj = contentofileasstring ;
}
Is my assumption of the usage of code contracts and exceptions right in this case. Do you think it is logical to replace the exception with a code contract(or vice versa)?
code not tested.Just an example scenario
I would probably go for an implementation which looks like the following:
private void ReadContent(string path)
{
Contract.Requires<FileMissingException>(File.Exists(path));
string content = filehelperobj.GetContent(path);
m_xmlobj = content;
}
Post Edit
As it's the content you want to validate, I would put a Contract.Ensures(!String.IsNullOrEmpty(Contract.Result<string>())); inside the filehelperobj.GetContent(string) method. Then if the content being read was null or empty, I would throw an exception. e.g.
public string GetContent(string path)
{
Contract.Requires<FileMissingException>(File.Exists(path));
Contract.Ensures(!String.IsNullOrEmpty(Contract.Result<string>()));
using(var reader = new StreamReader(File.OpenRead(path)))
{
var content = reader.ReadToEnd();
if(String.IsNullOrEmpty(content))
throw new FileContentException("No content found at file: " + path);
return content;
}
}
Well assuming you had the lines the wrong way round (ie, test the path for null before trying to use it) then yes, it is a valid pre-condition and therefore should be a code contract.

Categories