Add to List from XElement in foreach loop - c#

Program.cs
using ConsoleApp2.Models;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
string City_Name = "GdaƄsk";
var doc = XElement.Load($"https://maps.googleapis.com/maps/api/place/textsearch/xml?key={key}&query=restaurants+in+{City_Name}&language=pl&fields=place_id");
List<PlaceIdModel> IdList = doc.Descendants("result").Select(n => new PlaceIdModel
{
PlaceId = n.Element("place_id").Value
}).ToList();
List<PlaceDetailsModel> placeDetailsModel = new List<PlaceDetailsModel>();
foreach (var item in IdList)
{
var doc2 = XElement.Load($"https://maps.googleapis.com/maps/api/place/details/xml?key={key}&place_id={item.PlaceId}&language=pl&fields=name,vicinity,geometry/location,rating,website,opening_hours/weekday_text");
placeDetailsModel = doc2.Descendants("result").Select(x => new PlaceDetailsModel
{
Name = x.Element("name").Value,
Vicinity = x.Element("vicinity").Value,
Rating = x.Element("rating").Value,
Website = x.Element("website").Value,
Lat = x.Element("geometry").Element("location").Element("lat").Value,
Lng = x.Element("geometry").Element("location").Element("lng").Value,
Opening_hours = x.Descendants("weekday_text").Select(y => y.Value).ToList()
}).ToList();
};
}
}
}
PlaceIdModel.cs
namespace ConsoleApp2.Models
{
public class PlaceIdModel
{
public string PlaceId { get; set; }
}
}
PlaceDetailsModel.cs
using System.Collections.Generic;
namespace ConsoleApp2.Models
{
public class PlaceDetailsModel
{
public string Name { get; set; }
public string Vicinity { get; set; }
public string Rating { get; set; }
public string Website { get; set; }
public string Lat { get; set; }
public string Lng { get; set; }
public List<string> Opening_hours { get; set; }
}
}
I'm using goole API places. First I get place_id from city then I want to use loop foreach to save details of every place into list. Everytime everything save on [0] instead populate whole list.

With .ToList() you are creating a new list every time. Instead add the items to the existing list with the List.AddRange(IEnumerable) Method.
var placeDetailsModel = new List<PlaceDetailsModel>();
foreach (var item in IdList)
{
var doc2 = XElement.Load($"https://maps.googleapis.com/maps/...");
placeDetailsModel.AddRange(
doc2.Descendants("result")
.Select(x => new PlaceDetailsModel
{
Name = x.Element("name").Value,
Vicinity = x.Element("vicinity").Value,
Rating = x.Element("rating").Value,
Website = x.Element("website").Value,
Lat = x.Element("geometry").Element("location").Element("lat").Value,
Lng = x.Element("geometry").Element("location").Element("lng").Value,
Opening_hours = x.Descendants("weekday_text").Select(y => y.Value).ToList()
})
);
}
You do not need the .ToList() when reading the IdList. The foreach works well with an IEnumerable<T> and it saves you an unnecessary memory allocation.:
IEnumerable<PlaceIdModel> IdList = doc
.Descendants("result")
.Select(n => new PlaceIdModel
{
PlaceId = n.Element("place_id").Value
});
...
foreach (var item in IdList) ...
I also do not see the advantage of having a PlaceIdModel class just to store the Id temporarily. Just use the values directly:
var IdList = doc
.Descendants("result")
.Select(n => n.Element("place_id").Value);
...
foreach (var id in IdList) {
var doc2 = XElement.Load($"https://maps.googleapis.com/...&place_id={id}&language=...");
...
}

Related

How do I sort the csv file alphabetically and how to not show the "hidden" ones in the console with my code

I need to sort my csv file alphabetically and not show the ones that it says "hidden" for (aka. client 4 and client 5) this is the code:
static void Main(string[] args)
{
ReadCSFVFile();
Console.WriteLine();
}
static void ReadCSFVFile()
{
var lines = File.ReadAllLines("Navigation.txt");
var list = new List<Company>();
foreach (var line in lines)
{
var values = line.Split(';' );
var company = new Company() { ID = values[0], MenuName = values[1], ParentID = values[2], IsHidden = values[3], LinkURL = values[4] };
list.Add(company);
}
list.ForEach(x => Console.WriteLine($"{x.ID}\t {x.MenuName}\t {x.ParentID}\t {x.IsHidden}\t {x.LinkURL}"));
}
public class Company
{
public string ID { get; set; }
public string MenuName { get; set; }
public string ParentID { get; set; }
public string IsHidden { get; set; }
public string LinkURL { get; set; }
}
and this is the csv file:
ID;MenuName;ParentID;isHidden;LinkURL
1;Company;NULL;False; /company
2;About Us;1;False; /company/aboutus
3;Mission;1;False; /company/mission
4;Team;2;False; /company/aboutus/team
5;Client 2;10;False; /references/client2
6;Client 1;10;False; /references/client1
7;Client 4;10;True; /references/client4
8;Client 5;10;True; /references/client5
10;References;NULL;False; /references
The below should achieve this for you. I've commented the parts I've added to help out.
list.OrderBy(x => x.MenuName) // Order alphabetically based on MenuName
.Where(x => x.IsHidden != "True") // Filter only for non-hidden items
.ToList().ForEach(
x => Console.WriteLine($"{x.ID}\t {x.MenuName}\t {x.ParentID}\t{x.IsHidden}\t {x.LinkURL}"));

C# Flaten a nested list to list of different object for display in a datagrid

I'm having an issue presenting my nested collection in a WPF Datagrid.
bellow is the code that is giving me the desired result, but I wonder if it is possible to make it simpler?
public async Task LoadRecepi(short id)
{
Recepi = await _recepiDataService.Get(id);
var flat = new List<FlatRecepi1>();
foreach (var step in Recepi.Step)
{
flat.Add(new FlatRecepi1 {
RecepiId = step.RecepiId,
StepId = step.SPTagId,
Activity = step.Activity,
PVTagName = step.PVTag.Name
});
foreach (var node in step.Nodes)
{
flat.Add(new FlatRecepi1
{
StepId = node.SPTagId,
SPTagName = node.SPTag.Name,
PVTagName = node.PVTag.Name
});
}
}
}
thankyou so much for your help.
public class FlatRecepi1
{
public short RecepiId { get; set; }
public short StepId { get; set; }
public Activity Activity { get; set; }
public short NodeId { get; set; }
public string StepName { get; set; }
public string PVTagName { get; set; }
public string SPTagName { get; set; }
public Operator Operator { get; set; }
}
You can use a combination of Enumerable.SelectMany and Enumerable.Prepend.
The following code will project out each step's nodes into a collection of FlatRecepi1 and then prepend the FlatRecepi1 corresponding to the step at the start of the collection. Finally, the SelectMany flattens this "collection of collections" into a single list. This should give you the same ordering as the current code.
var flat = Recepi.Step.SelectMany(step =>
step.Nodes.Select(node => new FlatRecepi1 {
StepId = node.SPTagId,
SPTagName = node.SPTag.Name,
PVTagName = node.PVTag.Name
}).Prepend(new FlatRecepi1 {
RecepiId = step.RecepiId,
StepId = step.SPTagId,
Activity = step.Activity,
PVTagName = step.PVTag.Name,
})
).ToList();
If Prepend is not available to you because you are using an older framework, we can achieve the same with Enumerable.Concat:
var flat = Recepi.Step.SelectMany(step =>
new [] {
new FlatRecepi1 {
RecepiId = step.RecepiId,
StepId = step.SPTagId,
Activity = step.Activity,
PVTagName = step.PVTag.Name,
}
}.Concat(
step.Nodes.Select(node => new FlatRecepi1 {
StepId = node.SPTagId,
SPTagName = node.SPTag.Name,
PVTagName = node.PVTag.Name
})
)
).ToList();

ElasticSearch easy example doesn't work c#

ElasticSearch documentation is far from decent, so I ask here after reading them.
I've put up the easiest elasticsearch example after looking at their horrific documentation.
I got local elasticsearch client (starts on localhost:9200) and NEST library to try and put up a simple console program that indexes some files and try to search them by name.
Can someone help me and tell me why I don't find any result?
using Nest;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ElasticHorror
{
class Program
{
static void Main(string[] args)
{
Uri connectionString = new Uri("http://localhost:9200");
//Client settings, index must be lowercase
var settings = new ConnectionSettings(connectionString).DefaultIndex("tests");
settings.PrettyJson();
settings.ThrowExceptions();
//Client initialization
var client = new ElasticClient(settings);
//Index creation, I use a forced bool for testing in a console program only ;)
bool firstRun = true;
if (firstRun)
{
foreach(string file in Directory.GetFiles(#"G:\SomeFolderWithFiles", "*.*", SearchOption.AllDirectories))
{
Console.WriteLine($"Indexing document {file}");
client.IndexDocument<FileProps>(new FileProps(new FileInfo(file)));
}
}
var searchResponse = client.Search<FileProps>(s => s.Query(
doc => doc.Term(t => t.Name, "Test")))
.Documents;
}
internal class FileProps
{
public FileProps(FileInfo x)
{
CreationTime = x.CreationTime;
Extension = x.Extension;
FullName = x.FullName;
Lenght = x.Length;
Name = x.Name;
Directory = x.DirectoryName;
}
[Date]
public DateTime CreationTime { get; private set; }
public string Extension { get; private set; }
public string FullName { get; private set; }
public long Lenght { get; private set; }
public string Name;
public string Directory;
}
}
}
Thanks
Simple Example For You
Model
internal class Person
{
public int id { get; set; }
public string firstname { get; set; }
public string lastname { get; set; }
public string Mnumber { get; set; }
public string Email { get; set; }
}
var settings = new ConnectionSettings(new Uri("http://localhost:9200"));
settings.DefaultIndex("bar");
var client = new ElasticClient(settings);
var person = new Person
{
id = 2,
firstname = "Martijn123Hitesh",
lastname = "Martijn123",
Mnumber="97224261678",
Email="hitesh#gmail.com"
};
var indexedResult = client.Index(person, i => i.Index("bar"));
var searchResponse = client.Search<Person>(s => s
.Index("bar")
.Query(q => q
.Match(m => m
.Field(f => f.firstname)
.Query("Martijn123Hitesh")
)
)
);
Like Query in Elastic search Example
var searchResponseww = client.Search<Person>(s => s
.Index("bar")
.Query(q => q
.Bool(b => b
.Should(m => m
.Wildcard(c => c
.Field("firstname").Value("Martijn123".ToLower() + "*")
)))));

C# Parse items from namespace

I have the following XML:
https://pastebin.com/YQBhNzm5
I want to match up the item values with the field values.
XmlDocument xdoc = new XmlDocument();
xdoc.Load(ofd.FileName);
XmlNamespaceManager xmanager = new XmlNamespaceManager(xdoc.NameTable);
xmanager.AddNamespace("ns", "http://www.canto.com/ns/Export/1.0");
var result = xdoc.SelectNodes("//ns:Layout/ns:Fields", xmanager);
foreach(XmlElement item in result)
{
Console.WriteLine(item.InnerText);
}
When I do this I get all the field names in one line. How can I iterate through all fields in layout and go one by one?
I parsed xml using xml linq. First I put items into a dictionary. Then I parsed the fields looking up the uid from the dictionary. I parsed the fields recursively to keep the hierarchy.
It looks like the uid, type, value, and name are always the same for each item, but an item can appear in multiple catalogs with a catalog id and an id.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
Layout layout = new Layout(FILENAME);
}
}
public class Layout
{
public string tablename { get; set; }
public List<Field> fields { get; set; }
public Layout layout { get; set; }
public Dictionary<string, Item> dict = new Dictionary<string, Item>();
public Layout() { }
public Layout(string filename)
{
XDocument doc = XDocument.Load(filename);
XElement xLayout = doc.Descendants().Where(x => x.Name.LocalName == "Layout").FirstOrDefault();
XNamespace ns = xLayout.GetNamespaceOfPrefix("ns");
foreach (XElement item in doc.Descendants(ns + "Item"))
{
int catalogid = (int)item.Attribute("catalogid");
int id = (int)item.Attribute("id");
foreach(XElement fieldValue in item.Elements(ns + "FieldValue"))
{
string uid = (string)fieldValue.Attribute("uid");
uid = uid.Replace("{", "");
uid = uid.Replace("}", "");
string innertext = (string)fieldValue;
string displayValue = (string)fieldValue.Attribute("displayValue");
List<string> categoryValues = fieldValue.Elements(ns + "CategoryValue").Select(x => (string)x).ToList();
if (!dict.ContainsKey(uid))
{
Item newItem = new Item() {
catalogidId = new List<KeyValuePair<int, int>>() {new KeyValuePair<int, int>(catalogid, id)},
innertext = innertext,
uid = uid,
displayValue = displayValue,
categoryValues = categoryValues
};
dict.Add(uid, newItem);
}
else
{
dict[uid].catalogidId.Add(new KeyValuePair<int, int>(catalogid, id));
}
}
}
layout = new Layout();
RecursiveParse(ns, xLayout, layout);
}
public void RecursiveParse(XNamespace ns, XElement parent, Layout layout)
{
layout.tablename = (string)parent.Attribute("tableName");
foreach(XElement xField in parent.Element(ns + "Fields").Elements(ns + "Field"))
{
if (layout.fields == null) layout.fields = new List<Field>();
Field newField = new Field();
layout.fields.Add(newField);
newField.uid = (string)xField.Attribute("uid");
newField.uid = newField.uid.Replace("{", "");
newField.uid = newField.uid.Replace("}", "");
newField._type = (int)xField.Attribute("type");
newField.value = (int)xField.Attribute("valueInterpretation");
newField.name = (string)xField.Element(ns + "Name");
if (dict.ContainsKey(newField.uid))
{
newField.items = dict[newField.uid];
}
if (xField.Element(ns + "Layout") != null)
{
Layout newLayout = new Layout();
newField.layout = newLayout;
RecursiveParse(ns, xField.Element(ns + "Layout"), newLayout);
}
}
}
public class Field
{
public string uid { get; set; }
public int _type { get; set; }
public int value { get; set; }
public string name { get; set; }
public Layout layout { get; set; }
public Item items { get; set; }
}
public class Item
{
public List<KeyValuePair<int, int>> catalogidId { get; set; }
public string uid { get; set; }
public string innertext { get; set; }
public string displayValue { get; set; }
public List<string> categoryValues { get; set; }
}
}
}

parse xml children nodes

What is the best way to parse XML children nodes into a specific list? This is a small example of the XML.
<Area Name="Grey Bathroom" IntegrationID="3" OccupancyGroupAssignedToID="141">
<Outputs>
<Output Name="Light/Exhaust Fan" IntegrationID="46" OutputType="NON_DIM" Wattage="0" />
</Outputs>
</Area>
I want to create a list or something that will be called the Area Name and hold the information of the Output Name and IntegrationID. So I can call the list and pull out the Output Name and IntegrationID.
I can create a list of all Area Names and then a list of Outputs but cannot figure out how to create a list that will be called "Grey Bathroom" and hold the output "Light/Exhaust Fan" with an ID of 46.
XDocument doc = XDocument.Load(#"E:\a\b.xml");
List<Area> result = new List<Area>();
foreach (var item in doc.Elements("Area"))
{
var tmp = new Area();
tmp.Name = item.Attribute("Name").Value;
tmp.IntegrationID = int.Parse(item.Attribute("IntegrationID").Value);
tmp.OccupancyGroupAssignedToID = int.Parse(item.Attribute("OccupancyGroupAssignedToID").Value);
foreach (var bitem in item.Elements("Outputs"))
{
foreach (var citem in bitem.Elements("Output"))
{
tmp.Outputs.Add(new Output
{
IntegrationID = int.Parse(citem.Attribute("IntegrationID").Value),
Name = citem.Attribute("Name").Value,
OutputType = citem.Attribute("OutputType").Value,
Wattage = int.Parse(citem.Attribute("Wattage").Value)
});
}
}
result.Add(tmp);
}
public class Area
{
public String Name { get; set; }
public int IntegrationID { get; set; }
public int OccupancyGroupAssignedToID { get; set; }
public List<Output> Outputs = new List<Output>();
}
public class Output
{
public String Name { get; set; }
public int IntegrationID { get; set; }
public String OutputType { get; set; }
public int Wattage { get; set; }
}
The example uses an anonymous type. You could (and I warmly advice you to) use your own.
var doc = XDocument.Parse(xml);
var areaLists = doc.Elements("Area").
Select(e => e.Descendants("Output").
Select(d => new
{
Name = (string) d.Attribute("Name"),
Id = (int) d.Attribute("IntegrationID")
}).
ToArray()).
ToList();

Categories