I am using Newtonsoft.Json to Deserialize json string to Object, but I can't judge if the node is null or not. eg. jo["data"]["prevtime"], sometimes json has the node of ["prevtime"], sometimes doesn't have ["prevtime"]. If ["prevtime"] is null, it will report an error.
var jo = JObject.Parse(content);
if (jo["data"].ToString() == "")
return new StatusCollection();
var jInfo = jo["data"]["info"];
StatusCollection list = new StatusCollection();
Status status = null;
if (jInfo != null)
{
foreach (var j in jInfo.Children())
{
if (jo["data"]["prevtime"] != null)
{
status.Nexttime = jo["data"]["nexttime"].ToString();
status.Prevtime = jo["data"]["prevtime"].ToString();
}
status = j.ToObject<Status>();
if (!string.IsNullOrEmpty(status.Head))
{
status.Head += "/50";
}
if (!string.IsNullOrEmpty(status.From))
{
status.From = "来自" + status.From;
}
list.Add(status);
}
}
In the current version, it would be like :
if (jo["data"].Select***Token***("prevtime") != null)
{
status.Prevtime = jo["data"].Value<string>("prevtime");
status.Nexttime = jo["data"].Value<string>("nexttime");
}
Try to select the token you want, and there is a property to get the token value
if (jo["data"].Select("prevtime") != null)
{
status.Prevtime = jo["data"].Value<string>("prevtime");
status.Nexttime = jo["data"].Value<string>("nexttime");
}
JSON.NET Documentation:
Link 1
Link 2
Related
I have data stored in a DB field acting as a cache from an API call.
This data is either of the type:
MyObject
List<MyObject>
I currently have the following code which uses NewtonSoft.JSON to take the string and (based on a successful deserialization) determine which of those types the string is.
var _lstObj = new List<MyObject>();
var _obj = new MyObject();
bool isList = false;
try
{
var n = JsonConvert.DeserializeObject<List<MyObject>>(cacheString);
if(n!=null && n.Count()>0)
{
_lstObj = n;
isList = true;
}
}
catch(Exception e)
{
isList = false;
}
if (!isList)
{
try
{
var x = JsonConvert.DeserializeObject<MyObject>(cacheString);
if (x != null && x.Data != null)
{
_obj = x;
}
}
catch(Exception e) { }
}
This feels kind of cumbersome...is there a better way to do this?
I'll always have a string for the incoming data.
It will only ever be 1 of those 2 types.
This should work:
var obj = (JToken)JsonConvert.DeserializeObject(cacheString);
if (obj.Type == JTokenType.Array)
{
var result = obj.ToObject<List<MyObject>>();
}
else
{
var result = obj.ToObject<MyObject>();
}
Checking first if the json string is a list should solve the problem.
if (cacheString.StartsWith("["))
{
var myList = JsonConvert.DeserializeObject<List<MyObject>>(cacheString);
}
else
{
var myObject = JsonConvert.DeserializeObject<MyObject>(cacheString);
}
I would use the expando object, that way you can keep adding properties if you like dynamically.
dynamic exp = new ExpandoObject();
try
{
exp.isList = true;
exp.value = JsonConvert.DeserializeObject<List<MyObject>>(cacheString);
}
catch (Exception e)
{
exp.isList = false;
exp.value = JsonConvert.DeserializeObject<MyObject>(cacheString);
}
but ideally I would cache the object as a List regardless if its one or many.
I need help to get data from the site. I use geckofx in my application. I want it to retrieve text data from the xpath location after loading the page
XPathResult xpathResult = geckoWebBrowser1.Document.EvaluateXPath("/html/body/table[3]/tbody/tr[1]/td[2]/a[1]");
IEnumerable<GeckoNode> foundNodes = xpathResult.GetNodes();
How to download data as text?
It looks like you are struggling to retrieve the text from the GeckoFX objects.
Here are a few calls and operations that should get you started:
//get by XPath
XPathResult xpathResult = _browser.Document.EvaluateXPath("//*[#id]/div/p[2]");
var foundNodes = xpathResult.GetNodes();
foreach (var node in foundNodes)
{
var x = node.TextContent; // get text text contained by this node (including children)
GeckoHtmlElement element = node as GeckoHtmlElement; //cast to access.. inner/outerHtml
string inner = element.InnerHtml;
string outer = element.OuterHtml;
//iterate child nodes
foreach (var child in node.ChildNodes)
{
}
}
//get by id
GeckoHtmlElement htmlElementById = _browser.Document.GetHtmlElementById("mw-content-text");
//get by tag
GeckoElementCollection byTag = _browser.Document.GetElementsByTagName("input");
foreach (var ele in byTag)
{
var y = ele.GetAttribute("value");
}
//get by class
var byClass = _browser.Document.GetElementsByClassName("input");
foreach (var node in byClass)
{
//...
}
//cast to a different object
var username = ((GeckoInputElement)_browser.Document.GetHtmlElementById("yourUsername")).Value;
//create new object from DomObject
var button = new GeckoButtonElement(_browser.Document.GetElementById("myBtn").DomObject);
public string extract(string xpath, string type)
{
string result = string.Empty;
GeckoHtmlElement elm = null;
GeckoWebBrowser wb = geckoWebBrowser1;//(GeckoWebBrowser)GetCurrentWB();
if (wb != null)
{
elm = GetElement(wb, xpath);
if (elm != null)
//UpdateUrlAbsolute(wb.Document, elm);
if (elm != null)
{
switch (type)
{
case "html":
result = elm.OuterHtml;
break;
case "text":
if (elm.GetType().Name == "GeckoTextAreaElement")
{
result = ((GeckoTextAreaElement)elm).Value;
}
else
{
result = elm.TextContent.Trim();
}
break;
case "value":
result = ((GeckoInputElement)elm).Value;
break;
default:
result = extractData(elm, type);
break;
}
}
}
return result;
}
private string extractData(GeckoHtmlElement ele, string attribute)
{
var result = string.Empty;
if (ele != null)
{
var tmp = ele.GetAttribute(attribute);
/*if (tmp == null)
{
tmp = extractData(ele.Parent, attribute);
}*/
if (tmp != null)
result = tmp.Trim();
}
return result;
}
private object GetCurrentWB()
{
if (tabControl1.SelectedTab != null)
{
if(tabControl1.SelectedTab.Controls.Count > 0)
//if (tabControl1.SelectedTab.Controls.Count > 0)
{
Control ctr = tabControl1.SelectedTab.Controls[0];
if (ctr != null)
{
return ctr as object;
}
}
}
return null;
}
private GeckoHtmlElement GetElement(GeckoWebBrowser wb, string xpath)
{
GeckoHtmlElement elm = null;
if (xpath.StartsWith("/"))
{
if (xpath.Contains("#class") || xpath.Contains("#data-type"))
{
var html = GetHtmlFromGeckoDocument(wb.Document);
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(html);
var node = doc.DocumentNode.SelectSingleNode(xpath);
if (node != null)
{
var currentXpath = "/" + node.XPath;
elm = (GeckoHtmlElement)wb.Document.EvaluateXPath(currentXpath).GetNodes().FirstOrDefault();
}
}
else
{
elm = (GeckoHtmlElement)wb.Document.EvaluateXPath(xpath).GetNodes().FirstOrDefault();
}
}
else
{
elm = (GeckoHtmlElement)wb.Document.GetElementById(xpath);
}
return elm;
}
private string GetHtmlFromGeckoDocument(GeckoDocument doc)
{
var result = string.Empty;
GeckoHtmlElement element = null;
var geckoDomElement = doc.DocumentElement;
if (geckoDomElement is GeckoHtmlElement)
{
element = (GeckoHtmlElement)geckoDomElement;
result = element.InnerHtml;
}
return result;
}
private void button5_Click(object sender, EventArgs e)
{
var text = extract("/html/body/table[3]/tbody/tr[1]/td[2]/a[2]", "text");
MessageBox.Show(text);
}
I also insert the code from which I used a little longer code but it also works. maybe someone will need it. The creator of the code is Đinh Công Thắng, Web Automation App,
Regards
Hi I am trying to parse the response from a OSM webservice into feature collection using GeoJson.Net
I am new to GeoJSON and not able to identify how to do so:
The Json response can be find here. The code I have written is:
System.IO.StreamReader file = new System.IO.StreamReader(filepath);
string content = file.ReadToEnd();
file.Close();
dynamic deserialized = JsonConvert.DeserializeObject(content);
List<Feature> lstGeoLocation = new List<Feature>();
foreach (JObject item in deserialized.features)
{
//var feature = new Feature();
var geom = item.Property("geometry").Value;
}
But this will be plain JSON parsing and there might be a better way to parse the same.
I also tried NetTopologySuite JSON extension but when i use following code it gives me exception
"Expected token 'type' not found."
System.IO.StreamReader file = new System.IO.StreamReader(filepath);
string content = file.ReadToEnd();
file.Close();
var reader = new NetTopologySuite.IO.GeoJsonReader();
var featureCollection = reader.Read <NetTopologySuite.Features.FeatureCollection>(content);
I hate to answer my I question but after two days of hit & trial I get it working with both NetTopology and GeoJson
// get the JSON file content
var josnData = File.ReadAllText(destinationFileName);
// create NetTopology JSON reader
var reader = new NetTopologySuite.IO.GeoJsonReader();
// pass geoJson's FeatureCollection to read all the features
var featureCollection = reader.Read<GeoJSON.Net.Feature.FeatureCollection>(josnData);
// if feature collection is null then return
if (featureCollection == null)
{
return;
}
// loop through all the parsed featurd
for (int featureIndex = 0;
featureIndex < featureCollection.Features.Count;
featureIndex++)
{
// get json feature
var jsonFeature = featureCollection.Features[featureIndex];
Geometry geom = null;
// get geometry type to create appropriate geometry
switch (jsonFeature.Geometry.Type)
{
case GeoJSONObjectType.Point:
break;
case GeoJSONObjectType.MultiPoint:
break;
case GeoJSONObjectType.LineString:
break;
case GeoJSONObjectType.MultiLineString:
break;
case GeoJSONObjectType.Polygon:
{
var polygon = jsonFeature.Geometry as GeoJSON.Net.Geometry.Polygon;
var coordinates = new List <Point3D>();
foreach (var ring in polygon.Coordinates)
{
if (ring.IsLinearRing())
{
foreach (var coordinate in ring.Coordinates)
{
var location = coordinate as GeographicPosition;
if (location == null)
{
continue;
}
coordinates.Add(new Point3D(location.Longitude,
location.Latitude,
location.Altitude.HasValue ? location.Altitude.Value : 0 ));
}
}
}
geom = new Polygon(new LinearRing(new CoordinateSequence(coordinates.ToArray())),
null);
}
break;
case GeoJSONObjectType.MultiPolygon:
break;
case GeoJSONObjectType.GeometryCollection:
break;
case GeoJSONObjectType.Feature:
break;
case GeoJSONObjectType.FeatureCollection:
break;
default:
throw new ArgumentOutOfRangeException();
}
}
//Steps to Converting GeoJSON response to FeatureCollection
//1. Add NetTopologySuite.IO.GeoJson package from Nuget Package Manager.
//2. Write Following Code Snap:
string Filepath = "Your filepath here";
var josnData = File.ReadAllText(Filepath);
var reader = new NetTopologySuite.IO.GeoJsonReader();
var featureCollection =
reader.Read<GeoJSON.Net.Feature.FeatureCollection>(josnData);
//in my case i did it like this
for (int fIndex = 0; fIndex < featureCollection.Features.Count; fIndex++)
{
var AreaDetails =
featureCollection.Features[fIndex].Properties;
for (int AIndex = 0; AIndex < AreaDetails.Count;
AIndex++)
{
var element = AreaDetails.ElementAt(AIndex);
var Key = element.Key;
var Value = element.Value;
if (Key == "GML_ID")
{
areaDetails.StateCode = Value.ToString();
}
else if (Key == "STNAME")
{
areaDetails.State = Value.ToString();
}
else if (Key == "DISTFULL")
{
areaDetails.DistrictCode = Value.ToString();
}
else if (Key == "DTNAME")
{
areaDetails.District = Value.ToString();
}
else if (Key == "IPCODE")
{
areaDetails.TalukaCode = Value.ToString();
}
else if (Key == "IPNAME")
{
areaDetails.Taluka = Value.ToString();
}
else if (Key == "VLGCD2001")
{
areaDetails.AreaCode = Value.ToString();
}
else if (Key == "VILLNAME")
{
areaDetails.AreaName = Value.ToString();
}
}
var AreaCoords = featureCollection.Features[fIndex].Geometry;
var Type = AreaCoords.Type;
LocationDetails locationDetails = new LocationDetails();
if (Type == GeoJSONObjectType.Polygon)
{
var polygon = AreaCoords as GeoJSON.Net.Geometry.Polygon;
var polygonCoords = polygon.Coordinates[0].Coordinates;
for (int AIndex = 0; AIndex < polygonCoords.Count; AIndex++)
{
locationDetails.lat = Convert.ToDecimal(polygonCoords[AIndex].Latitude);
locationDetails.lng = Convert.ToDecimal(polygonCoords[AIndex].Longitude);
locationDetailsList.Add(locationDetails);
}
}
Trying to convert that:
const string maj = "variable";
in
const string MAJ = "variable";
I'm using a Diagnostic with CodeFix.
I've already done the Diagnostic:
var localDeclarationConst = node as LocalDeclarationStatementSyntax;
if (localDeclarationConst != null &&
localDeclarationConst.Modifiers.Any(SyntaxKind.ConstKeyword)
)
{
foreach (VariableDeclaratorSyntax variable in localDeclarationConst.Declaration.Variables)
{
var symbol = model.GetDeclaredSymbol(variable);
if (symbol != null)
{
string varName = symbol.Name;
if (!varName.Equals(varName.ToUpper()))
{
addDiagnostic(Diagnostic.Create(Rule, localDeclarationConst.GetLocation(), "Les constantes doivent être en majusucle"));
}
}
}
}
But I cannot find a way for the CodeFix. Here is what I already wrote:
if (token.IsKind(SyntaxKind.ConstKeyword))
{
var ConstClause = (LocalDeclarationStatementSyntax)token.Parent;
var test = ConstClause.GetText();
var newConstClause = ConstClause.With //What with this With ??
var newRoot = root.ReplaceNode(ConstClause, newConstClause);
return new[] { CodeAction.Create("Mettre en maj", document.WithSyntaxRoot(newRoot)) };
}
As you can see, I'm looking for something that I can use with the .With
Edit:
So, I begin to understand how it works. But there is a point that I cannot know how it works. Let me explain:
if (token.IsKind(SyntaxKind.ConstKeyword))
{
var ConstClause = (VariableDeclaratorSyntax)token.Parent;
var test = ConstClause.Identifier.Text;
var newConstClause = ConstClause.ReplaceToken(SyntaxFactory.Identifier(test), SyntaxFactory.Identifier(test.ToUpperInvariant()));
var newRoot = root.ReplaceNode(ConstClause, newConstClause);
return new[] { CodeAction.Create("Make upper", document.WithSyntaxRoot(newRoot)) };
}
Here it's what I've done. To acces to the name of the variable (ConstClause.Identifier.Text) I use a VariableDeclaratorSyntax instead of the LocalDeclarationStatementSyntax.
But it doesn't work. What does I have to use??
It will be very helpful, because I will know how to change the name of my variables. And I need that.
Try ReplaceToken() instead of a With method.
Also, in your diagnostic, you could just use VariableDeclarator.Identifier instead of forcing the symbol to be created with GetDeclaredSymbol.
Okey, I'll find a way a now it works!
Here is the Diagnostic:
var localDeclarationConst = node as LocalDeclarationStatementSyntax;
if (localDeclarationConst != null &&
localDeclarationConst.Modifiers.Any(SyntaxKind.ConstKeyword)
)
{
foreach (VariableDeclaratorSyntax variable in localDeclarationConst.Declaration.Variables)
{
string varName = variable.Identifier.Text;
if (!varName.Equals(varName.ToUpper()))
{
addDiagnostic(Diagnostic.Create(Rule, variable.GetLocation(), "Les constantes doivent être en majusucle"));
}
}
And here is the CodeFix:
var root = await document.GetSyntaxRootAsync(cancellationToken); (root)
var token = root.FindToken(span.Start);
var node = root.FindNode(span);
if (node.IsKind(SyntaxKind.VariableDeclarator))
{
if (token.IsKind(SyntaxKind.IdentifierToken))
{
var variable = (VariableDeclaratorSyntax)node;
string newName = variable.Identifier.ValueText;
string NameDone = String.Empty;
for (int i = 0; i < newName.Length; i++)
{
NameDone = NameDone.ToString() + char.ToUpper(newName[i]);
}
var leading = variable.Identifier.LeadingTrivia;
var trailing = variable.Identifier.TrailingTrivia;
VariableDeclaratorSyntax newVariable = variable.WithIdentifier(SyntaxFactory.Identifier(leading, NameDone, trailing));
var newRoot = root.ReplaceNode(variable, newVariable);
return new[] { CodeAction.Create("Make upper", document.WithSyntaxRoot(newRoot)) };
}
}
If something looks wrong tell me, but I tried it and it works!
Here's my ICommand:
public ICommand ConfirmLotSavedCommand {
get
{
return new RelayCommand(ConfirmLotSaved);
}
}
The problem is I have deserialized data that I want to store into database after a user clicks confirm button. If the user does not click on confirm or the lot number already exists, then I don't want to save the deserialized string in db.
I had trouble calling a function with one parameter inside my ConfirmLotSaved() method because of scope.
So I created a set the deserialized lot as a field and put the code to save to db inside of ConfirmLotSaved(). However, the field is null for some strange reason... I'm not sure why.
Here's my attempt:
private LotInformation lot; //field that is supposed to contain all the deserialized info
private void ConfirmLotSaved()
{
using (var db = new DDataContext())
{
bool lotNumDbExists = db.LotInformation.Any(r => r.lot_number == DeserialLotNumber);
if (lotNumDbExists == false)
{
successWindow.Message = "Successfully Saved Lot";
dialogService.ShowDialog(successWindow.Message, successWindow);
LotInformation newLot = new LotInformation();
if (newLot != null)
{
newLot.Id = lot.Id;
newLot.lot_number = lot.lot_number;
newLot.exp_date = lot.exp_date;
LotNumber = Lot.lot_number;
ExpirationDate = Lot.exp_date.ToString();
foreach (Components comp in lot.Components)
{
newLot.Components.Add(comp);
}
ComponentsList = newLot.Components;
foreach (Families fam in lot.Families)
{
newLot.Families.Add(fam);
}
FamiliesList = newLot.Families;
try
{
db.LotInformation.Add(newLot);
db.SaveChanges();
//Grabs the lot_number column from db that is distinct
var lotNum = db.LotInformation.GroupBy(i => i.lot_number).Select(group => group.FirstOrDefault());
//Loops through the lot numbers column in db and converts to list
foreach (var item in lotNum)
{
Console.WriteLine(item.lot_number);
}
LotNumList = lotNum.ToList();
Console.WriteLine("successfully");
}
catch
{
//TODO: Add a Dialog Here
}
}
else if (lotNumDbExists == true)
{
// Inform user that the lot_number already exists
errorWindow.Message = LanguageResources.Resource.Lot_Exists_Already;
dialogService.ShowDialog(LanguageResources.Resource.Error, errorWindow);
logger.writeErrLog(LanguageResources.Resource.Lot_Exists_Already);
return;
}
}
}
}
Deserialization function to see where lot is grabbing data:
public void DeserializedStream(string filePath)
{
XmlRootAttribute xRoot = new XmlRootAttribute();
xRoot.ElementName = "lot_information";
xRoot.IsNullable = false;
// Create an instance of lotinformation class.
LotInformation lot = new LotInformation();
// Create an instance of stream writer.
TextReader txtReader = new StreamReader(filePath);
// Create and instance of XmlSerializer class.
XmlSerializer xmlSerializer = new XmlSerializer(typeof(LotInformation), xRoot);
// DeSerialize from the StreamReader
lot = (LotInformation)xmlSerializer.Deserialize(txtReader);
// Close the stream reader
txtReader.Close();
LotInformation newList = new LotInformation();
using (var db = new DDataContext())
{
bool isDuplicate = db.LotInformation.Any(r => r.lot_number == lot.lot_number);
if (newList != null && isDuplicate == false)
{
newList.Id = lot.Id;
newList.lot_number = lot.lot_number;
newList.exp_date = lot.exp_date;
DeserialLotNumber = newList.lot_number;
DeserialExpirationDate = newList.exp_date.ToString();
foreach (Component comp in lot.Components)
{
newList.Components.Add(comp);
}
DeserialComponentsList = newList.Components;
foreach (Families fam in lot.Families)
{
newList.Families.Add(fam);
}
DeserialFamiliesList = newList.Families;
}
else if (isDuplicate == true)
{
DeserialAnalytesList = null;
DeserialFamiliesList = null;
// Inform user that the lot_number already exists
errorWindow.Message = LanguageResources.Resource.Lot_Exists_Already;
dialogService.ShowDialog(LanguageResources.Resource.Error, errorWindow);
logger.writeErrLog(LanguageResources.Resource.Lot_Exists_Already);
return;
}
}
}
I figured out what was wrong:
After setting private LotInformation lot; field before constructor, I redeclared locally my mistake:
LotInformation lot = new LotInformation();
Changed it to:
lot = new LotInformation();
and it works.
I suggest you to use RelayCommand's generic edition http://www.kellydun.com/wpf-relaycommand-with-parameter/
It will allow you to pass lot to your command from view, all you need to store lot in current DataContext.