I'm writing a web service in C#. For that I am making API calls to PVGIS. This API documentation for Monthly solar radiation values specifies it responds with BASIC TEXT data or CSV data but the API response gives tabular view in any case. I need this response converted to C# array or object.
I've tried all methods people have specified in answers to other similar questions.
API response:
Latitude (decimal degrees): 45.000
Longitude (decimal degrees): 8.000
Radiation database: PVGIS-CMSAF
Optimal slope angle (deg.):
Year Month Hh
2005 Jan 56.5
2005 Feb 75.7
2005 Mar 118
2005 Apr 131
2005 May 193
2005 Jun 211
2005 Jul 217
2005 Aug 179
2005 Sep 115
2005 Oct 72.9
2005 Nov 42.4
2005 Dec 39.4
2006 Jan 51.3
2006 Feb 58.6
2006 Mar 118
2006 Apr 147
2006 May 167
2006 Jun 215
...
I'm using this piece of code
JavaScriptSerializer ser = new JavaScriptSerializer();
string json = ser.Serialize(response.Content);
And the response I get is:
"Latitude (decimal degrees):\t0.000\r\nLongitude (decimal degrees):\t0.000\r\nRadiation database:\tPVGIS-CMSAF\r\nOptimal slope angle (deg.):\t\r\n\r\nYear\t\t Month\t\tHh\r\n2005\t\tJan\t\t0\r\n2005\t\tFeb\t\t0\r\n2005\t\tMar\t\t0\r\n2005\t\tApr\t\t0\r\n2005\t\tMay\t\t0\r\n2005\t\tJun\t\t0\r\n2005\t\tJul\t\t0\r\n2005\t\tAug\t\t0\r\n2005\t\tSep\t\t0\r\n2005\t\tOct\t\t0\r\n2005\t\tNov\t\t0\r\n2005\t\tDec\t\t0\r\n2006\t\tJan\t\t0\r\n2006\t\tFeb\t\t0\r\n2006\t\tMar\t\t0\r\n2006\t\tApr\t\t0\r\n2006\t\tMay\t\t0\r\n2006\t\tJun\t\t0\r\n2006\t\tJul\t\t0\r\n2006\t\tAug\t\t0\r\n2006\t\tSep\t\t0\r\n2006\t\tOct\t\t0\r\n2006\t\tNov\t\t0\r\n2006\t\tDec\t\t0\r\n2007\t\tJan\t\t0\r\n2007\t\tFeb\t\t0\r\n2007\t\tMar\t\t0\r\n2007\t\tApr\t\t0\r\n2007\t\tMay\t\t0\r\n2007\t\tJun\t\t0\r\n2007\t\tJul\t\t0\r\n2007\t\tAug\t\t0\r\n2007\t\tSep\t\t0\r\n2007\t\tOct\t\t0\r\n2007\t\tNov\t\t0\r\n2007\t\tDec\t\t0\r\n2008\t\tJan\t\t0\r\n2008\t\tFeb\t\t0\r\n2008\t\tMar\t\t0\r\n2008\t\tApr\t\t0\r\n2008\t\tMay\t\t0\r\n2008\t\tJun\t\t0\r\n2008\t\tJul\t\t0\r\n2008\t\tAug\t\t0\r\n2008\t\tSep\t\t0\r\n2008\t\tOct\t\t0\r\n2008\t\tNov\t\t0\r\n2008\t\tDec\t\t0\r\n2009\t\tJan\t\t0\r\n2009\t\tFeb\t\t0\r\n2009\t\tMar\t\t0\r\n2009\t\tApr\t\t0\r\n2009\t\tMay\t\t0\r\n2009\t\tJun\t\t0\r\n2009\t\tJul\t\t0\r\n2009\t\tAug\t\t0\r\n2009\t\tSep\t\t0\r\n2009\t\tOct\t\t0\r\n2009\t\tNov\t\t0\r\n2009\t\tDec\t\t0\r\n2010\t\tJan\t\t0\r\n2010\t\tFeb\t\t0\r\n2010\t\tMar\t\t0\r\n2010\t\tApr\t\t0\r\n2010\t\tMay\t\t0\r\n2010\t\tJun\t\t0\r\n2010\t\tJul\t\t0\r\n2010\t\tAug\t\t0\r\n2010\t\tSep\t\t0\r\n2010\t\tOct\t\t0\r\n2010\t\tNov\t\t0\r\n2010\t\tDec\t\t0\r\n2011\t\tJan\t\t0\r\n2011\t\tFeb\t\t0\r\n2011\t\tMar\t\t0\r\n2011\t\tApr\t\t0\r\n2011\t\tMay\t\t0\r\n2011\t\tJun\t\t0\r\n2011\t\tJul\t\t0\r\n2011\t\tAug\t\t0\r\n2011\t\tSep\t\t0\r\n2011\t\tOct\t\t0\r\n2011\t\tNov\t\t0\r\n2011\t\tDec\t\t0\r\n2012\t\tJan\t\t0\r\n2012\t\tFeb\t\t0\r\n2012\t\tMar\t\t0\r\n2012\t\tApr\t\t0\r\n2012\t\tMay\t\t0\r\n2012\t\tJun\t\t0\r\n2012\t\tJul\t\t0\r\n2012\t\tAug\t\t0\r\n2012\t\tSep\t\t0\r\n2012\t\tOct\t\t0\r\n2012\t\tNov\t\t0\r\n2012\t\tDec\t\t0\r\n2013\t\tJan\t\t0\r\n2013\t\tFeb\t\t0\r\n2013\t\tMar\t\t0\r\n2013\t\tApr\t\t0\r\n2013\t\tMay\t\t0\r\n2013\t\tJun\t\t0\r\n2013\t\tJul\t\t0\r\n2013\t\tAug\t\t0\r\n2013\t\tSep\t\t0\r\n2013\t\tOct\t\t0\r\n2013\t\tNov\t\t0\r\n2013\t\tDec\t\t0\r\n2014\t\tJan\t\t0\r\n2014\t\tFeb\t\t0\r\n2014\t\tMar\t\t0\r\n2014\t\tApr\t\t0\r\n2014\t\tMay\t\t0\r\n2014\t\tJun\t\t0\r\n2014\t\tJul\t\t0\r\n2014\t\tAug\t\t0\r\n2014\t\tSep\t\t0\r\n2014\t\tOct\t\t0\r\n2014\t\tNov\t\t0\r\n2014\t\tDec\t\t0\r\n2015\t\tJan\t\t0\r\n2015\t\tFeb\t\t0\r\n2015\t\tMar\t\t0\r\n2015\t\tApr\t\t0\r\n2015\t\tMay\t\t0\r\n2015\t\tJun\t\t0\r\n2015\t\tJul\t\t0\r\n2015\t\tAug\t\t0\r\n2015\t\tSep\t\t0\r\n2015\t\tOct\t\t0\r\n2015\t\tNov\t\t0\r\n2015\t\tDec\t\t0\r\nHh: Irradiation on horizontal plane (kWh/m2)\r\n\r\nPVGIS (c) European Communities, 2001-2016"
I expect the output to be either JSON object that I can convert to C# object or if possible converting response directly to C# array or object.
Wow, if you can request the API to respond with json or xml you can make short work of this - but if it really is just tabular text then life becomes a bit more complicated as you need to manually parse the data and convert it into objects.
Let's consider an example object that you might target, containing a collection of another custom type. (Have used list for convenience as we may not know the length of the expected data, you can substitute this for a HashSet if preferred, or even swap things around a bit make this a private collection with a public method that returns it as an array if array is what you need to make use of etc. Also you can change the member types as needed).
public class ApiData
{
public decimal Latitude { get; set; }
public decimal Longitude { get; set; }
public string RadiationDatabase { get; set; }
public List<ApiSlopeAngle> OptimalSlopeAngle { get; set; }
public ApiData()
{
OptimalSlopeAngle = new List<ApiSlopeAngle>();
}
}
Here is the nested object.
public class ApiSlopeAngle
{
public int Year { get; set; }
public string Month { get; set; }
public decimal Hh { get; set; }
public ApiSlopeAngle(int year, string month, decimal hh)
{
Year = year;
Month = month;
Hh = hh;
}
}
Here is some shortened sample data.
// Sample data
string apiStringData = "Latitude (decimal degrees):\t45.000\r\nLongitude (decimal degrees):\t8.000\r\nRadiation database:\tPVGIS-CMSAF\r\nOptimal slope angle (deg.):\t\r\n\r\nYear\t\t Month\t\tHh\r\n2005\t\tJan\t\t56.5\r\n2005\t\tFeb\t\t75.7\r\n2005\t\tMar\t\t118\r\n2005\t\tApr\t\t131\r\n2005\t\tMay\t\t193\r\n2005\t\tJun\t\t211\r\n2005\t\tJul\t\t217\r\n2005\t\tAug\t\t179\r\n2005\t\tSep\t\t115\r\n2005\t\tOct\t\t72.9\r\n2005\t\tNov\t\t42.4\r\nHh: Irradiation on horizontal plane(kWh/ m2)\r\n\r\nPVGIS(c) European Communities, 2001 - 2016";
Now to parse the sample data with Regex.... Disclaimer - code for example only and contains minimal checking which assumes the data format is consistent. Also my Regex is really basic!
// Define the regex patterns to use
string lattPattern = "(Latitude\\s\\(decimal\\sdegrees\\):)(\\t\\d+\\.*\\d*)";
string longPattern = "(Longitude\\s\\(decimal\\sdegrees\\):)(\\t\\d+\\.*\\d*)";
string radDbPattern = "(Radiation\\sdatabase\\:)(\\t)(PVGIS\\-CMSAF)";
string osaPattern = "((19|20)\\d{2})(\\t\\t)([A-Z]+[a-z]*)(\\t\\t\\d+\\.*\\d*)";
// Create the matches for the top-level data
var lattitude = Regex.Match(apiStringData, lattPattern);
var longitude = Regex.Match(apiStringData, longPattern);
var radDb = Regex.Match(apiStringData, radDbPattern);
// Create the result object, and populate the top-level properties
ApiData apiObject = new ApiData();
apiObject.Latitude = Convert.ToDecimal(lattitude.Groups[2].ToString());
apiObject.Longitude = Convert.ToDecimal(longitude.Groups[2].ToString());
apiObject.RadiationDatabase = radDb.Groups[3].ToString();
// Split the sample data into an array
// to make it easier to enumerate what will become the nested data
string[] apiArray = Regex.Split(apiStringData, "\r\n");
// Step through it
foreach (string s in apiArray)
{
var angle = Regex.Match(s, osaPattern, RegexOptions.IgnoreCase);
if (angle.Success == true)
{
// Create the properties
int year = Convert.ToInt32(angle.Groups[1].ToString());
string month = angle.Groups[4].ToString();
decimal hh = Convert.ToDecimal(angle.Groups[5].ToString());
// Add to the collection
ApiSlopeAngle apiDate = new ApiSlopeAngle(year, month, hh);
apiObject.OptimalSlopeAngle.Add(apiDate);
}
}
Again, just to emphasise, lots of room for improvement here, happy for anyone to make better work of this!