I have a windows form in C# that does a httpclient get request. And this is the response in XML format
> <Result><Success>true</Success><Token>MYTOKENHERE</Token><TokenExpirationDate null="1"
> /><UserName>********</UserName><PersonCode>442078</PersonCode><LoginStatusMessage>LoginOk</LoginStatusMessage></Result>
I want to set the text of a text box to what is inbetween the <Token></Token> Tags
What is the best approach to do this
Thanks
This is my current Form1.cs code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net.Http;
using System.Xml.Serialization;
namespace EBS_Token_Form
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
HttpClient Client = new HttpClient();
Client.BaseAddress = new Uri("PRIVATE_URL");
string Username = username.Text;
string Password = password.Text;
string CredentialsString = $"{Username}:{Password}";
byte[] CredentialsStringByes = System.Text.Encoding.UTF8.GetBytes(CredentialsString);
Client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("basic", Convert.ToBase64String(CredentialsStringByes));
try
{
var Response = Client.GetAsync("Rest/Authentication").Result;
if (!Response.IsSuccessStatusCode)
{
// Something went wrong, is error.
// Put a breakpoint on the line below and we can figure out why.
string x = "";
}
string ServerResponse = Response.Content.ReadAsStringAsync().Result;
}
catch (Exception ex)
{
return;
}
}
If i set the value of the textbox to ServerResponse it has the full xml document. I need to extract just the .
Usually I'd use XmlSerializer for something like this, but if you really just need this one value, you may want to try XElement:
var root = XElement.Parse(yourResponseString);
var value = root.Element("Token")?.Value;
XElement is great for traversing, reading and manipulating XML.
XPath works for this, although some might consider overkill. The XPath expression /Result/Token/Text() does exactly what it looks like it will.
using System.Xml;
using System.Xml.XPath;
string Incoming_XML = #"<Result><Success>true</Success><Token>MYTOKENHERE</Token><TokenExpirationDate null=""1"" /><UserName>********</UserName><PersonCode>442078</PersonCode><LoginStatusMessage>LoginOk</LoginStatusMessage></Result>";
XPathDocument xPathDoc = null;
using (StringReader sr = new StringReader(Incoming_XML))
{
xPathDoc = new XPathDocument(sr);
XPathNavigator xPathNav = xPathDoc.CreateNavigator();
string Result = xPathNav.SelectSingleNode("/Result/Token/text()").Value;
Console.WriteLine($"Token is: {Result}");
}
below sample code may not the best but it is simple to understand and will do the work.
// Define a regular expression pattern
string Regex_syntax = #"<Token>[\s\S]*?</Token>";
Regex rx = new Regex(Regex_syntax,RegexOptions.Compiled | RegexOptions.IgnoreCase);
// Define a RAW data string to process , in your case will be http response result
string inputtext = #"<Result><Success>true</Success><Token>MYTOKENHERE</Token><TokenExpirationDate";
// Find matches.
MatchCollection matches = rx.Matches(inputtext);
// clease the uneeded string
string cleanseString = matches[0].ToString().Replace(#"<Token>", "");
cleanseString = cleanseString.Replace(#"</Token>", "");
// This will print value in between the token tag
Console.WriteLine("require output = " + cleanseString);
Related
I have an XML-encoded attribute value. This is actually from a processing instruction. So the original data looks something like this:
<root><?pi key="value" data="<foo attr="bar">Hello world</foo>" ?></root>
I can parse it like this:
using System;
using System.Linq;
using System.Xml.Linq;
public class Program
{
private const string RawData = #"<root><?pi key=""value"" data=""<foo attr="bar">Hello world</foo>"" ?></root>";
public static void Main()
{
XDocument doc = GetXDocumentFromProcessingInstruction();
IEnumerable<XElement> fooElements = doc.Descendants("foo");
// ...
}
private static XProcessingInstruction LoadProcessingInstruction()
{
XDocument doc = XDocument.Parse(rawData);
return doc
.DescendantNodes()
.OfType<XProcessingInstruction>()
.First();
}
private static XDocument GetXDocumentFromProcessingInstruction()
{
XProcessingInstruction processingInstruction = LoadProcessingInstruction();
// QUESTION:
// Can there ever be a situation where HtmlDecode wouldn't decode the XML correctly?
string decodedXml = WebUtility.HtmlDecode(processingInstruction.Data);
// This works well, but it contains the attributes of the processing
// instruction as text.
string dummyXml = $"<dummy>{xml}</dummy>";
return XDocument.Parse(dummyXml);
}
This works absolutely fine, as far as I can tell.
But I am wondering if there might be some edge cases where it may fail, because of differences in how data would be encoded in XML vs. HTML.
Anybody have some more insight?
Edit:
Sorry, I made some incorrect assumptions about XProcessingInstruction.Data, but the code above was still working fine, so my question stands.
I have nonetheless rewritten my code and wrapped everything in an XElement, which (of course) removed the issue altogether:
private static XDocument GetXDocumentFromProcessingInstruction2()
{
XProcessingInstruction processingInstruction = LoadProcessingInstruction();
string encodedXml = string.Format("<dummy {0} />", processingInstruction.Data);
XElement element = XElement.Parse(encodedXml);
string parsedXml = element.Attribute("data").Value;
return XDocument.Parse(parsedXml);
}
So this does exactly what I need. But since WebUtility.HtmlDecode worked sufficiently well, I would still like to know if there could have been a situation where the first approach could have failed.
Removing the question marks and adding a forward slash at end of your input I got this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string input = "<pi data=\"<foo attr="bar">Hello world</foo>\" />";
XElement pi = XElement.Parse(input);
string data = (string)pi.Attribute("data");
XElement foo = XElement.Parse(data);
string attr = (string)foo.Attribute("attr");
string innertext = (string)foo;
}
}
}
So I want to write a BTC converter app, I can get the value of it for £1 at https://blockchain.info/tobtc?currency=GBP&value=1
And changing the GBP to USD in the URL changed it to USD naturally, I want to use this and parse the data into a variable and then have it used as a normal. But I want the user to be able to enter their currency and have the url change and then fetch the amounnt in say one canadian dollar. How can I use the GBP as a variable and then have it change depending on user input.
I'm thinking a dropdown box of most popular currencys but I wouldn't know how to use that at all.
Be kind, I'm a noob and trying to make my first useful application
Here is a simply example how you can get the value for the different currencies:
using System;
using System.Net.Http;
using System.Threading.Tasks;
namespace ConsoleApp5
{
public class Program
{
static void Main(string[] args)
{
Console.WriteLine(GetValueAsync("GBP").Result);
Console.WriteLine(GetValueAsync("USD").Result);
Console.WriteLine(GetValueAsync("RUB").Result);
}
public static async Task<string> GetValueAsync(string curr)
{
using (HttpClient client = new HttpClient())
{
var responseString = await client.GetStringAsync("https://blockchain.info/tobtc?currency="+curr+"&value=1");
return responseString;
}
}
}
}
Here
client.GetStringAsync("https://blockchain.info/tobtc?currency="+curr+"&value=1");
is sending asynchronous http get request by the provided URL and returning response as a string.
The site you want to use is returning just the value as a string that's why this is working.
As the request is asynchronous we must use await so that we get response in string.
If you want to do this in WinForm. Here is example. Let's assume that you have already TextBox for input value, Label for showing result and Button for Getting result. They can be added by just drop and down from Toolbox to your form.
using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp3
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private async void button1_ClickAsync(object sender, EventArgs e)
{
string curr = textBox1.Text;
if (!string.IsNullOrEmpty(curr))
{
label2.Text = "waiting for response";
var res = await GetValueAsync(curr);
label2.Text = res;
}
}
public async Task<string> GetValueAsync(string curr)
{
var responseString = string.Empty;
using (HttpClient client = new HttpClient())
{
string reqString = "https://blockchain.info/tobtc?currency=" + curr + "&value=1";
responseString = await client.GetStringAsync(reqString);
}
return responseString;
}
}
}
Here is the full solution for Win Forms link
Here are useful links for you:
MSDN HttpClient GetStringAsync
WinForm with Async Methods
MSDN C# String Concatenation
MSDN WinForms Click Event
Here is a recording how to do this also:
Recording
I am trying to get second attribute value of a meta tag using an xpath expression in html agility pack:
The meta tag:
<meta name="pubdate" content="2012-08-30" />
The xml path expression i am using:
//meta[#name='pubdate']/#content
But it does not return anything. I tried to search around and implement this solution:
//meta[#name='pubdate']/string(#content)
Another way:
string(//meta[#name='pubdate']/#content)
But it gives xml exception in html agility pack.
Another solution did not work as well.
//meta[#name='pubdate']/data(#content)
For reasons i wanted to use just xml path (and not html agility pack functions to get the attribute value). The function i use is below:
date = TextfromOneNode(document.DocumentNode.SelectSingleNode(".//body"), "meta[#name='pubdate']/#content");
public static string TextfromOneNode(HtmlNode node, string xmlPath)
{
string toReturn = "";
if(node.SelectSingleNode(xmlPath) != null)
{
toReturn = node.SelectSingleNode(xmlPath).InnerText;
}
return toReturn;
}
So far it looks like there is no way to use xml path expression to get an attribute value directly.
Any ideas?
There is a way using HtmlNodeNavigator :
public static string TextfromOneNode(HtmlNode node, string xmlPath)
{
string toReturn = "";
var navigator = (HtmlAgilityPack.HtmlNodeNavigator)node.CreateNavigator();
var result = navigator.SelectSingleNode(xmlPath);
if(result != null)
{
toReturn = result.Value;
}
return toReturn;
}
The following console app example demonstrates how HtmlNodeNavigator.SelectSingleNode() works with both XPath that return element and XPath that return attribute :
var raw = #"<div>
<meta name='pubdate' content='2012-08-30' />
<span>foo</span>
</div>";
var doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(raw);
var navigator = (HtmlAgilityPack.HtmlNodeNavigator)doc.CreateNavigator();
var xpath1 = "//meta[#name='pubdate']/#content";
var xpath2 = "//span";
var result = navigator.SelectSingleNode(xpath1);
Console.WriteLine(result.Value);
result = navigator.SelectSingleNode(xpath2);
Console.WriteLine(result.Value);
dotnetfiddle demo
output :
2012-08-30
foo
Using xml linq
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string input = "<meta name=\"pubdate\" content=\"2012-08-30\" />";
XElement meta = XElement.Parse(input);
DateTime output = (DateTime)meta.Attribute("content");
}
}
}
Below is what I use to log into the database using linq and then I use C# expressions to gather the data I want. The next thing I want to do is convert this data into an XML any Ideas?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Data;
namespace VcacManagementTools.BuildProfiles
{
public static class BuildProfileTools
{
public static ICollection<string> GetExistingBuildProfileNames(string repositoryHostname,
string repositoryUsername,
string repositoryPassword)
{
var url = string.Format("https://{0}/repository/data/ManagementModelEntiti.svc", repositoryHostname);
var managementModelClient = new DynamicOps.ManagementModel.ManagementModelEntities(new Uri(url))
{
Credentials = new NetworkCredential(repositoryUsername, repositoryPassword)
};
return managementModelClient
.GlobalProfiles
.Select(gp => gp.ProfileName)
.ToList();
The Output I recieve is a list of values
If I understood you well, you want to take the data (the list contains the data from the database) and put it in XML file. I used variables to show where to put each data.
In case you have an XML:
try
{
doc = XDocument.Load(spath, LoadOptions.SetBaseUri);
foreach(String propertyData in dataList)
{
XElement root = new XElement(ElementName);
root.Add(new XElement("property1", propertyData));
doc.Element(MainElement).Add(root);
}
doc.Save(spath);
}
catch (Exception)
{
}
Please people help me out I need to consume a web service that returns an xml from my application, The code that downloads xml works fine, but I need to extract values from the xml file, but I keep getting a null return value from the code, precisely the GetLocationFromXml() method is the method returning null, the GetLocationAsXMLFromHost() method works fine.
this is the complete class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AMIS.Core.DTOs;
using System.Net;
using System.Xml.Linq;
using System.Xml;
using System.Linq;
public class GeoLocationService
{
private string _hostWebSite = "http://api.hostip.info";
private readonly XNamespace _hostNameSpace = "http://www.hostip.info/api";
private readonly XNamespace _hostGmlNameSpace = "http://www.opengis.net/gml";
public LocationInfo GetLocationInfoFromIPAddress(string userHostIpAddress)
{
IPAddress ipAddress = null;
IPAddress.TryParse(userHostIpAddress, out ipAddress);
string xmlData = GetLocationAsXMLFromHost(ipAddress.ToString());
LocationInfo locationInfo = GetLocationFromXml(xmlData);
return locationInfo;
}
private string GetLocationAsXMLFromHost(string userHostIpAddress)
{
WebClient webClient= new WebClient();
string formattedUrl = string.Format(_hostWebSite + "/?ip={0}", userHostIpAddress);
var xmlData = webClient.DownloadString(formattedUrl);
return xmlData;
}
private LocationInfo GetLocationFromXml(string xmlData)
{
LocationInfo locationInfo = new LocationInfo();
var xmlResponse = XDocument.Parse(xmlData);
var nameSpace = (XNamespace)_hostNameSpace;
var gmlNameSpace = (XNamespace)_hostGmlNameSpace;
try
{
locationInfo = (from x in xmlResponse.Descendants(nameSpace + "Hostip")
select new LocationInfo
{
CountryName = x.Element(nameSpace + "countryName").Value,
CountryAbbreviation = x.Element(nameSpace + "countryAbbrev").Value,
LocationInCountry = x.Element(gmlNameSpace + "name").Value
}).SingleOrDefault();
}
catch (Exception)
{
throw;
}
return locationInfo;
}
}
and the xml file is below
<?xml version="1.0" encoding="iso-8859-1"?>
<HostipLookupResultSet version="1.0.1" xmlns:gml="http://www.opengis.net/gml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.hostip.info/api/hostip-1.0.1.xsd">
<gml:description>This is the Hostip Lookup Service</gml:description>
<gml:name>hostip</gml:name>
<gml:boundedBy>
<gml:Null>inapplicable</gml:Null>
</gml:boundedBy>
<gml:featureMember>
<Hostip>
<ip>41.78.8.3</ip>
<gml:name>(Unknown city)</gml:name>
<countryName>NIGERIA</countryName>
<countryAbbrev>NG</countryAbbrev>
<!-- Co-ordinates are unavailable -->
</Hostip>
</gml:featureMember>
</HostipLookupResultSet>
Given the comments, I suspect the problem may be as simple as:
private string _hostNameSpace = "hostip.info/api";
should be:
private string _hostNameSpace = "http://hostip.info/api";
(Ditto for the others.) Personally I'd make then XNamespace values to start with:
private static readonly XNamespace HostNameSpace = "http://hostip.info/api";
EDIT: Okay, after messing around with your example (which could have been a lot shorter and a lot more complete) I've worked out what's wrong: you're looking for elements using the "host namespace" - but the elements in the XML aren't in any namespace. Just get rid of those namespace bits, and it works fine.