Finding Root Url and Subsites Url In Collection - c#

I have a strong typed list string collection consistenting of root level sites sometimes represented at the domain level, however sometimes not. For example:
http://x.com
http://x.com/y
http://x.com/y/w
http://x.com/y/z
http://a.com/b/c
http://a.com/b/c/d
http://a.com/b/c/e
I need to convert the string collection to a collection of strongly typed custom objects, such as the below:
public class UrlObject
{
public string url { get; set; }
public List<UrlObject> subUrls { get; set; }
}
The amount of characters and slashes in the "Parent" url can vary, I am curious if there is a way that building a collection that allows flexible for the size of the "Parent".
The expected output of this method would be a list collection with two objects, represented below:
object 1
Parent - http://x.com
subUrls- http://x.com/y,
http://x.com/y/w,
http://x.com/y/z
object 2
Parent: http://a.com/b/c
subUrls-http://a.com/b/c/d,
http://a.com/b/c/e

There is a class that already exists in .NET that will make your life a lot easier: System.Uri. Instead of your custom class, you can create a "conatiner" class like this:
public class UriContainer
{
public Uri Parent { get; set; }
public List<Uri> Children { get; set; }
}
You can easily turn a collection of string urls into Uri objects with a little bit of LINQ:
var urlStringList = new List<string>()
{
"http://x.com",
"http://x.com/y",
"http://x.com/y/w",
"http://x.com/y/z",
"http://a.com/b/c",
"http://a.com/b/c/d",
"http://a.com/b/c/e"
};
IEnumerable<Uri> uris = urlStringList.Select(x => new Uri(x));
From there you can GroupBy() the Host property, then inside each group, OrderBy() the Segments.Length property. Then take the First() one (this is the one with the least segments aka the "parent" per your example), then you take the rest of them as the "children":
var containerList = new List<UriContainer>();
foreach(var groupedUri in uris.GroupBy(x => x.Host))
{
var sorted = groupedUri.OrderBy(x => x.Segments.Length);
containerList.Add(new UriContainer()
{
Parent = sorted.First(),
Children = sorted.Skip(1).ToList()
});
}
The above code will give you a structure like this:
http://x.com/
http://x.com/y
http://x.com/y/w
http://x.com/y/z
----------------------
http://a.com/b/c
http://a.com/b/c/d
http://a.com/b/c/e
----------------------
This code has very little error prevention, you might want to make sure items are not null and such but it at least gives you a starting point.
Fiddle here

Related

How to yield multiple objects with respect to a multi-valued column in Dynamic Linq

Scenario:
I have to export an excel file which will contain list of Parts. We have enabled the user to select the columns and get only selected columns' data in the exported file. Since this is a dynamic report, I am not using any concrete class to map the report as this will result in exporting empty column headers in the report, which is unnecessary. I am using Dynamic Linq to deal with this scenario.
I have a list of dynamic objects fetched from dynamic linq.
[
{"CleanPartNo":"Test","Description":"test","AliasPartNo":["258","145","2313","12322"]},
{"CleanPartNo":"Test1","Description":"test1","AliasPartNo":[]}
]
How can I get 4 rows out of this json like
Please note that I cannot use a strongly typed object to deserialize/ Map it using JSON.Net
Update
Following is the code:
public class Part
{
public int Id { get; set; }
public string CleanPartNo { get; set; }
public string Description { get; set; }
public List<PartAlias> AliasPartNo { get; set; }
}
public class PartAlias
{
public int PartId { get; set; }
public int PartAliasId { get; set; }
public string AliasPartNo { get; set; }
}
var aliases = new List<PartAlias> {
new PartAlias{AliasPartNo="258" },
new PartAlias{AliasPartNo="145" },
new PartAlias{AliasPartNo="2313" },
new PartAlias{AliasPartNo="12322" }
};
List<Part> results = new List<Part> {
new Part{CleanPartNo="Test", Description= "test", PartAlias=aliases },
new Part{CleanPartNo="Test1", Description= "test1" }
};
var filters = "CleanPartNo,Description, PartAlias.Select(AliasPartNo) as AliasPartNo";
var dynamicObject = JsonConvert.SerializeObject(results.AsQueryable().Select($"new ({filters})"));
in the dynamicObject variable I get the json mentioned above
Disclaimer: The following relies on anonymous classes, which is not exactly the same as dynamic LINQ (not at all), but I figured that it may help anyway, depending on your needs, hence I decided to post it.
To flatten your list, you could go with a nested Select, followed by a SelectMany (Disclaimer: This assumes that every part has at least one alias, see below for the full code)
var flattenedResult = result.Select(part => part.AliasPartNumber.Select(alias => new
{
CleanPartNo = part.CleanPartNo,
Description = part.Description,
AliasPartNo = alias.AliasPartNo
})
.SelectMany(part => part);
You are first projecting your items from result (outer Select). The projection projects each item to an IEnumerable of an anonymous type in which each item corresponds to an alias part number. Since the outer Select will yield an IEnumerable<IEnumerable> (or omething alike), we are using SelectMany to get a single IEnumerable of all the items from your nested IEnumerables. You can now serialize this IEnumerable of instances of an anonymous class with JsonConvert
var json = sonConvert.SerializeObject(flatResults);
Handling parts without aliases
If there are no aliases, the inner select will yield an empty IEnumerable, hence we will have to introduce a special case
var selector = (Part part) => part.AliasPartNumber?.Any() == true
? part.AliasPartNumber.Select(alias => new
{
CleanPartNo = part.CleanPartNo,
Description = part.Description,
AliasPartNo = alias.AliasPartNo
})
: new[]
{
new
{
CleanPartNo = part.CleanPartNo,
Description = part.Description,
AliasPartNo = alias.AliasPartNo
}
};
var flattenedResult = result.Select(selector).SelectMany(item => item);
From json you provided you can get values grouped by their name in this way:
var array = JArray.Parse(json);
var lookup = array.SelectMany(x => x.Children<JProperty>()).ToLookup(x => x.Name, x => x.Value);
then this is just a manner of simple loop over the lookup to fill the excel columns.
However, I would suggest to do the flatenning before JSON. I tried for some time to make it happen even without knowing the names of the columns that are arrays, but I failed, and since it's your job, I won't try anymore :P
I think the best way here would be to implement custom converter that would just multiply objects for properties that are arrays. If you do it well, you would get infinite levels completely for free.

Use C# Linq Lambda to combine fields from two objects into one, preferably without anonymous objects

I have a class setup like this:
public class Summary
{
public Geometry geometry { get; set; }
public SummaryAttributes attributes { get; set; }
}
public class SummaryAttributes
{
public int SERIAL_NO { get; set; }
public string District { get; set; }
}
public class Geometry
{
public List<List<List<double>>> paths { get; set; }
}
and i take a json string of records for that object and cram them in there like this:
List<Summary> oFeatures = reportObject.layers[0].features.ToObject<List<Summary>>();
my end goal is to create a csv file so i need one flat List of records to send to the csv writer i have.
I can do this:
List<SummaryAttributes> oAtts = oFeatures.Select(x => x.attributes).ToList();
and i get a nice List of the attributes and send that off to csv. Easy peasy.
What i want though is to also pluck a field off of the Geometry object as well and include that in my final List to go to csv.
So the final List going to the csv writer would contain objects with all of the fields from SummaryAttributes plus the first and last double values from the paths field on the Geometry object (paths[0][0][first] and paths[0][0][last])
It's hard to explain. I want to graft two extra attributes onto the original SummaryAttributes object.
I would be ok with creating a new SummaryAttributesXY class with the two extra fields if that's what it takes.
But i'm trying to avoid creating a new anonymous object and having to delimit every field in the SummaryAttributes class as there are many more than i have listed in this sample.
Any suggestions?
You can select new anonymous object with required fields, but you should be completely sure that paths has at least one item in each level of lists:
var query = oFeatures.Select(s => new {
s.attributes.SERIAL_NO,
s.attributes.District,
First = s.geometry.paths[0][0].First(), // or [0][0][0]
Last = s.geometry.paths[0][0].Last()
}).ToList()
Got it figured out. I include the X and Y fields in the original class definition. When the json gets deserialized they will be null. Then i loop back and fill them in.
List<Summary> oFeatures = reportObject.layers[0].features.ToObject<List<Summary>>();
List<Summary> summary = oFeatures.Select(s =>
{
var t = new Summary
{
attributes = s.attributes
};
t.attributes.XY1 = string.Format("{0} , {1}", s.geometry.paths[0][0].First(), s.geometry.paths[0][1].First());
t.attributes.XY2 = string.Format("{0} , {1}", s.geometry.paths[0][0].Last(), s.geometry.paths[0][1].First());
return t;
}).ToList();
List<SummaryAttributes> oAtts = summary.Select(x => x.attributes).ToList();

Dynamically deserializing to a property in RestSharp

I am playing with the Harvest API and I'm trying to automatically map the entities as easy as possible, unfortunately when I do a request like GET /projects it generates a result like so:
[{
project: {
name: "Test"
}
},
{
project: {
name: "Test 2"
}]
In RestSharp, I can't directly do this:
client.Execute<List<Project>>(request)
Because it is going to look for a property called Project. So I have to make another class that has that property, and call it like this:
client.Execute<List<ProjectContainer>>(request)
I don't want to make a 'container' class for every entity, so I thought I found a clever solution to make one class I can use on all:
public class ListContainer<T> where T : IHarvestEntity
{
public T Item { get; set; }
}
But, of course, the deserializer has no idea it needs to map the entity name (or "Project") to the property Item. In the restsharp documentation I found that I could use [DeserializeAs(Name = "CustomProperty")] to tell the deserializer which field to map to this property. However, attributes do only allow constants, which means I can't do:
[DeserializeAs(Name = typeof(T).FullName)]
public T Item { get; set; }
Does anyone know a clever solution to this? So i don't have to create 10 different container classes?
I suggest you use the XPath equivalent for Json. With Json.NET you can parse the string and create a dynamic object.
With SelectToken you can query values, or using Linq.
The code looks something like this (I did not test it):
// execute the request
RestResponse response = client.Execute(request);
var content = response.Content; // raw content as string
JObject o = JObject.Parse(content);
IList<string> projectNames = o.SelectToken("project").Select(s => (string)s.name).ToList();
You can code the paths or configure the paths anyway you like.
--- Edit ---
Here's an example that I tested, converting the json string to a list of projects.
var projects = JArray.Parse(response.Content).Select(r => new Project(r["project"]["name"].Value<string>())).ToList();
To keep it really simple, you can use List<dynamic> and access the property/properties by name with a one-liner.
var names = client.Execute<List<dynamic>>(request).Data.Select(
item => item["project"]["name"]).ToList(); // list of names
If this is not sufficient, then you could improvise your own mapper and extract a collection of e.g. Project instances:
var projects = client.Execute<List<dynamic>>(request).Data.Select(
item => Map<Project>(item)).ToList(); // list of Project instances
where Map method could be something like
public T Map<T>(dynamic item) where T : class
{
// inline for clarity
var mappings = new Dictionary<Type,Func<dynamic,object>>
{
{ typeof(Project), map => new Project(map["project"]["name"]) }
};
return (T)mappings[typeof(T)].Invoke(item);
}
given Project is defined as
public class Project
{
public Project(string name)
{
Name = name;
}
public string Name { get; set; }
}

Mapping JSON (jQuery) to KeyValuePair

I have a JSON object with numerous properties that I am submitting to a C# web service via jQuery.ajax() - it looks something like this:
var obj = {};
obj.LanguageCode = 1031;
obj.Gender = { 'Geschlecht': 'Mann' };
obj.City = { 'Stadt': 'Berlin' };
...
Some properties, like Gender and City, store a localized/translated prompt and response that I want to map to a KeyValuePair. I've tried formatting the Javascript in different ways, but the data only comes through when the datatype is Dictionary - when the datatype is KeyValuePair it doesn't work. For example:
private Dictionary Gender { get; set; } // works: Gender[0] == {[Geschlecht,Mann]}
private KeyValuePair City { get; set; } // doesn't work: City == {[,]}
I can use Dictionary if necessary since it works, but it seems like KeyValuePair is more appropriate and cleaner to use. Can you map Javascript objects to KeyValuePairs, or am I stuck with using Dictionary?
Looks like you need a collection of KeyValuePair objects, not a single one (even though your collection would only have one item) - that's all a Dictionary is, a collection with a few helpers around it.
But personally, I'd recommend building an actual class to represent your values, to organize it a little better - a little more verbose, but I think it's worth it.
// C#
public class LocalAndTranslated {
public string Localized { get;set; }
public string Translated { get;set; }
}
// JS
obj.Gender = { Localized: "Geschlecht", Translated: "Man" };
If you wanted to, you can even go so far as to define a "class" in javascript:
var LocalAndTranslated = (function() {
function LocalAndTranslated(localized, translated) {
this.Localized = localized;
this.Translated = translated;
}
return LocalAndTranslated;
})();
obj.Gender = new LocalAndTranslated("Geschlecht", "Man");

What would be the best way to generate the json below using a .net web service?

What would be the best way to generate the json below using a .net web service? I plan to call this though jquery on the front end.
I'm not seeing if I have to piece it together by hand or if there's an object structure in C# I could use that would equate to this when returned.
{'Option 1': {'Suboption':2},'Option 2': {'Suboption 2': {'Subsub 1':5, 'Subsub 2':6}}}
Right now I have the data formatted like this
Id | Text | ParentId
1 Option1 null
2 SubOption 1
3 Option2 null
4 SubOption2 3
5 SubSub1 4
6 SubSub2 4
But I can change the data structure if it would make it easier to generate the json.
EDIT
Final solution is loop with string builder to form up the JSON.
Thanks!
You need a recursive data structure to support the nesting.
public class Item
{
public int ID { get; set; }
public string Text { get; set; }
public Item SubItem { get; set; }
}
var myObject = new Item
{
Id = 1,
Text = "Some Text",
SubItem = new Item { Id = 2, Text = "SubItem" }
}
var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
string json = serializer.Serialize(myObject);
It looks like you're trying to serialize a tree-like structure, so you need to build a tree of some sort. You can maybe use something like this:
class Node
{
public String Text {get;set;}
public Node[] Children {get;set;}
public int Id {get;set;} // if you still need this
}
though it sort of reverses things (links to children instead of to parents).
Also, you can't achieve your exact output with this technique, because the keys are different at every level. Using a class like I have here means that the JSON keys will always be "Text", "Children" and "Id", but that should be enough.
If that's not what you want, you can always use a Dictionary<String, Object>, whose values are either strings or more dictionaries.

Categories

Resources