Parse() Can't Get All Element - c#

i have smailler XML file i want to parse it .
<?xml version="1.0" encoding="utf-8"?>
<!-- GeeSuth Checker Time -->
<Geranal>
<AftrNoon Min="20" StartAftrNoon="05:00:00" EndAftrNoon="11:01:00" />
<Night Min="50" StartNight="2:00:00" EndNight="6:00:00" />
<AlFajr Min="100" StartAlfajr="9:00:00" EndAlfajr="10:00:00" />
</Geranal>
i want to get all the value in line , like
<AftrNoon Min="20" StartAftrNoon="05:00:00" EndAftrNoon="11:01:00" />
i need save the values in string paramater :.
Min
StartAftrNoon
EndAftrNoon
and save it in paramater ?
im using this :.
XmlReader ReaderXML = XmlReader.Create("Date.xml");
while (ReaderXML.Read())
{
ReaderXML.IsStartElement("Geranal");
if (ReaderXML.NodeType == XmlNodeType.Element && ReaderXML.Name == "AftrNoon")
{
//AftarNoon Fill
txt_Min_Aftrnoon.Text = ReaderXML.GetAttribute(0);
dt_Aftr_start.Text = ReaderXML.GetAttribute(1);
dt_aftar_End.Text = ReaderXML.GetAttribute(2);
}
if (ReaderXML.NodeType == XmlNodeType.Element && ReaderXML.Name == "Night")
{
txt_Min_Night.Text = ReaderXML.GetAttribute(0);
dt_Night_Start.Text = ReaderXML.GetAttribute(1);
dt_Night_end.Text = ReaderXML.GetAttribute(2);
}
if (ReaderXML.NodeType == XmlNodeType.Element && ReaderXML.Name == "AlFajr")
{
txt_Min_Fajr.Text = ReaderXML.GetAttribute(0);
dt_Fajr_Start.Text = ReaderXML.GetAttribute(1);
dt_fajar_end.Text = ReaderXML.GetAttribute(2);
}
}
It's Not get all elements value.

Just put all name/value pairs to a dictionary. Using Linq2Xml
var values = XDocument.Load(filename)
.Descendants("AftrNoon")
.First()
.Attributes()
.ToDictionary(a => a.Name, a => a.Value);
Now you can access them like
var min = values["Min"];
or
foreach(var kv in values)
{
Console.WriteLine(kv.Key + ":" + kv.Value);
}

To start with your XML has a small issue with the naming of the attributes that makes it hard to parse - the element AlFajr has a capital F, yet the attributes do not. If you can fix that then this code works nicely:
var xd = XDocument.Load("Date.xml");
var nodes =
(
from e in xd.Root.Elements()
let Min = e.Attribute("Min").Value
let Start = e.Attribute("Start" + e.Name.LocalName).Value
let End = e.Attribute("End" + e.Name.LocalName).Value
select new { e.Name, Min, Start, End, }
).ToDictionary(x => x.Name, x => new { x.Min, x.Start, x.End });
That gives me this:
Now I can use that to populate your fields very easily:
txt_Min_Aftrnoon.Text = nodes["AftrNoon"].Min;
dt_Aftr_start.Text = nodes["AftrNoon"].Start;
dt_aftar_End.Text = nodes["AftrNoon"].End;
txt_Min_Night.Text = nodes["Night"].Min;
dt_Night_Start.Text = nodes["Night"].Start;
dt_Night_end.Text = nodes["Night"].End;
txt_Min_Fajr.Text = nodes["AlFajr"].Min;
dt_Fajr_Start.Text = nodes["AlFajr"].Start;
dt_fajar_end.Text = nodes["AlFajr"].End;
Alternatively, you could also set up a dictionary for your text boxes and, using the above code, assign the values like this:
var textBoxes = new []
{
new { Name = "AftrNoon", Min = txt_Min_Aftrnoon, Start = dt_Aftr_start, End = dt_aftar_End },
new { Name = "Night", Min = txt_Min_Night, Start = dt_Night_Start, End = dt_Night_end },
new { Name = "AlFajr", Min = txt_Min_Fajr, Start = dt_Fajr_Start, End = dt_fajar_end },
};
foreach (var tb in textBoxes)
{
tb.Min.Text = nodes[tb.Name].Min;
tb.Start.Text = nodes[tb.Name].Start;
tb.End.Text = nodes[tb.Name].End;
}
Another alternative, that eliminates the need to fix the attribute naming issue, is to just do this:
var xd = XDocument.Load("Date.xml");
txt_Min_Aftrnoon.Text = xd.Root.Element("AftrNoon").Attribute("Min").Value;
dt_Aftr_start.Text = xd.Root.Element("AftrNoon").Attribute("StartAftrNoon").Value;
dt_aftar_End.Text = xd.Root.Element("AftrNoon").Attribute("EndAftrNoon").Value;
txt_Min_Night.Text = xd.Root.Element("Night").Attribute("Min").Value;
dt_Night_Start.Text = xd.Root.Element("Night").Attribute("StartNight").Value;
dt_Night_end.Text = xd.Root.Element("Night").Attribute("EndNight").Value;
txt_Min_Fajr.Text = xd.Root.Element("AlFajr").Attribute("Min").Value;
dt_Fajr_Start.Text = xd.Root.Element("AlFajr").Attribute("StartAlfajr").Value;
dt_fajar_end.Text = xd.Root.Element("AlFajr").Attribute("EndAlfajr").Value;

Related

How to apply order by to linq query?

In c# linq, I have this code which works
private IQueryable<v_CompanyInquiryInfo> SearchCompany(string pCompanyName)
{
var mCompany = from d in db.v_CompanyInquiryInfo
where d.CompanyName.ToLower().Equals(pCompanyName)
select ((v_CompanyInquiryInfo)d);
return mCompany;
}
And I have this
private IQueryable SearchCompanies(string pValues)
{
string mValues = pValues;
foreach (string lWord in iRestrictedWords)
{
mValues.Replace(lWord, "");
}
var mSearchArray = pValues.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
var mCompanyCriteria = db.v_CompanyInquiryInfo.AsExpandable().Where(TradingInquiryController.CompanyContainsSearchTerms(mSearchArray));
var mCompanies = mCompanyCriteria
.Select(x => new
{
x.CompanyName,
x.CompanyID,
x.SearchTags,
Rank = mSearchArray.Sum(s => ((x.SearchTags.Length - x.SearchTags.Replace(s, "").Length) / s.Length))
});
var mResults = mCompanies.OrderByDescending(o => o.Rank).Skip(0).Take(20);
return mResults;
}
which also works. However I want the return type of this second function to be IQueryable<v_CompanyInquiryInfo>. The problem is there is a Rank new dynamic column added, and then I sort by it. How can I apply the same ordering but without creating a new column for it, then apply a cast to v_CompanyInquiryInfo. So that I can return IQueryable<v_CompanyInquiryInfo>. I can't figure out the syntax for this. Also it can return all columns.
Thanks
You don't need to create that property:
private IQueryable SearchCompanies(string pValues)
{
string mValues = pValues;
foreach (string lWord in iRestrictedWords)
{
mValues.Replace(lWord, "");
}
var mSearchArray = pValues.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
var mCompanyCriteria = db.v_CompanyInquiryInfo.AsExpandable().Where(TradingInquiryController.CompanyContainsSearchTerms(mSearchArray));
var mCompanies = mCompanyCriteria
.OrderByDescending(x => mSearchArray.Sum(s => ((x.SearchTags.Length - x.SearchTags.Replace(s, "").Length) / s.Length))
;
//var mResults = mCompanies.Skip(0).Take(20);
return mCompanies;
}

Filter products with ElasticSearch concat a lot of filter

I've been trying to filter products with Elasticsearch for a few hours, unfortunately to no avail.
I need to find products that belong to certain categories and at the same time have selected several brands and one size.
Help :(
json screen
querycontainer build method
private QueryContainer CreateOrQueryFromFilter(QueryContainer queryContainer, SortedSet<string> filter, string fieldName)
{
if (filter != null && filter.Count > 0)
{
foreach (var item in filter)
{
queryContainer |= new TermQuery()
{
Name = fieldName + "named_query",
Boost = 1.1,
Field = fieldName,
Value = item
};
}
}
return queryContainer;
}
and search method
public ResultModel SearchRequest(RequestModel r)
{
string key = string.Format("search-{0}-{1}", r.CacheKey + "-" + ProductCatalog.Model.Extension.StringHelper.UrlFriendly(r.SearchText), r.Prefix);
node = new Uri("http://xxxx:9200/");
settings = new ConnectionSettings(node);
settings.DisableDirectStreaming();
settings.DefaultIndex("products");
client = new ElasticClient(settings);
// return AppCache.Get(key, () =>
// {
DateTime start = DateTime.Now;
ResultModel result = new ResultModel(r.Canonical, r.RouteObject);
if (!string.IsNullOrEmpty(r.Prefix))
{
result.Prefix = r.Prefix;
}
QueryContainer c = new QueryContainer();
if (r.CategoryFilterChilds != null && r.CategoryFilterChilds.Count > 0)
{
var a1 = new SortedSet<string>(r.CategoryFilterChilds.Select(a => (string)a.ToString()));
c = CreateOrQueryFromFilter(c, a1, "categories");
}
else
{
if (r.CategoryFilterRoots != null && r.CategoryFilterRoots.Count > 0)
{
var a1 = new SortedSet<string>(r.CategoryFilterRoots.Select(a => (string)a.ToString()));
c = CreateOrQueryFromFilter(c, a1, "categories");
}
else
{
// null
}
}
var filters = new AggregationDictionary();
if (r.IsBrandFilter)
{
c = CreateOrQueryFromFilter(c, r.SelectedBrands, "brands");
}
if (r.IsColorFilter)
{
c = CreateOrQueryFromFilter(c, r.SelectedBrands, "colors");
}
int skip = (r.Page * r.PageSize) - r.PageSize;
ISearchRequest r2 = new SearchRequest("products");
r2.From = 1;
r2.Size = r.PageSize;
r2.Query = c;
string[] Fields = new[] { "brands", "shopId" };
AggregationBase aggregations = null;
foreach (string sField in Fields)
{
var termsAggregation = new TermsAggregation("agg_" + sField)
{
Field = sField,
Size = 120,
Order = new List<TermsOrder> { TermsOrder.TermDescending }
};
if (aggregations == null)
{
aggregations = termsAggregation;
}
else
{
aggregations &= termsAggregation;
}
}
r2.Aggregations = aggregations;
var c2 = client.Search<ShopProductElastic>(r2);
var ShopsBuf = (Nest.BucketAggregate)(c2.Aggregations["agg_brands"]);
var ShopsCount = ShopsBuf.Items.Count();
var results = c2;
result.BrandsRequest = new SortedDictionary<string, int>();
foreach (Nest.KeyedBucket<object> item in ShopsBuf.Items)
{
result.BrandsRequest.Add((string)item.Key, (int)(item.DocCount ?? 0));
}
result.CategorySelected = r.CategoryCurrent;
result.TotalCount = 10;
var costam = results.Documents.ToList();
var targetInstance = Mapper.Map<List<Products>>(costam);
result.Products = targetInstance;
result.Page = r.Page;
result.PageSize = r.PageSize;
result.IsBrandFilter = r.IsBrandFilter;
result.IsColorFilter = r.IsColorFilter;
result.IsPatternFilter = r.IsPatternFilter;
result.IsSeasonFilter = r.IsSeasonFilter;
result.IsShopFilter = r.IsShopFilter;
result.IsSizeFilter = r.IsSizeFilter;
result.IsStyleFilter = r.IsStyleFilter;
result.IsTextileFilter = r.IsTextileFilter;
DateTime stop = DateTime.Now;
result.SearchTime = stop - start;
result.SearchText = r.SearchText;
return result;
// }, TimeSpan.FromHours(8));
}
I have all products that have a given brand or categories. However, i need all products of a selected brand in selected categories

c# XML to linq error if null

I have a method that is parsing an XML file.
My method is:
public static List<UpperLevelGPS> ParseXml(string Document)
{
List<UpperLevelGPS> result = new List<UpperLevelGPS>();
result.Clear();
doc = XDocument.Load(Document);
result = (from n in doc.Descendants("level")
select new UpperLevelGPS()
{
CurrentLevel = int.Parse(n.Attribute("CurrentLevel").Value),
TeleNodes = (from l in n.Element("UpperLevelGPSs").Elements("UpperLevelGPS")
select new TeleNodes()
{
id = (int)(l.Attribute("id")),
UpperLevelGPSMapID = (int)l.Attribute("UpperLevelGPSMapID"),
DestinationMapID = (int)l.Attribute("DestinationMapID"),
HostelID = (int)l.Attribute("HostelID"),
x = (float)l.Attribute("x"),
y = (float)l.Attribute("y"),
z = (float)l.Attribute("z")
}).ToList()
}).ToList();
return result;
}
Node UpperLevelGPSs won't allways exists in my XML file, so above query fails. How can i catch and handle null event?
Check if it does before the linq statment:
public static List<UpperLevelGPS> ParseXml(string Document)
{
List<UpperLevelGPS> result = new List<UpperLevelGPS>();
result.Clear();
doc = XDocument.Load(Document);
var upperLevelGPSs = n.Element("UpperLevelGPSs");
if (upperLevelGPSs.Count > 0)
{
result = (from n in doc.Descendants("level")
select new UpperLevelGPS()
{
CurrentLevel = int.Parse(n.Attribute("CurrentLevel").Value),
TeleNodes = (from l in upperLevelGPSs .Elements("UpperLevelGPS")
select new TeleNodes()
{
id = (int)(l.Attribute("id")),
UpperLevelGPSMapID = (int)l.Attribute("UpperLevelGPSMapID"),
DestinationMapID = (int)l.Attribute("DestinationMapID"),
HostelID = (int)l.Attribute("HostelID"),
x = (float)l.Attribute("x"),
y = (float)l.Attribute("y"),
z = (float)l.Attribute("z")
}).ToList()
}).ToList();
}
return result;
}
Note: I have not tested this. Let me know if you have any issues.
{
id = (int)(l.Attribute("id")),
UpperLevelGPSMapID = (int?)l.Attribute("UpperLevelGPSMapID"),
DestinationMapID = (int)l.Attribute("DestinationMapID"),
HostelID = (int)l.Attribute("HostelID"),
x = (float)l.Attribute("x"),
y = (float)l.Attribute("y"),
z = (float)l.Attribute("z")
}).ToList()
}).ToList();
(Int?) Will result in null value if attribute in not present.

Determining value jumps in List<T>

I have a class:
public class ShipmentInformation
{
public string OuterNo { get; set; }
public long Start { get; set; }
public long End { get; set; }
}
I have a List<ShipmentInformation> variable called Results.
I then do:
List<ShipmentInformation> FinalResults = new List<ShipmentInformation>();
var OuterNumbers = Results.GroupBy(x => x.OuterNo);
foreach(var item in OuterNumbers)
{
var orderedData = item.OrderBy(x => x.Start);
ShipmentInformation shipment = new ShipmentInformation();
shipment.OuterNo = item.Key;
shipment.Start = orderedData.First().Start;
shipment.End = orderedData.Last().End;
FinalResults.Add(shipment);
}
The issue I have now is that within each grouped item I have various ShipmentInformation but the Start number may not be sequential by x. x can be 300 or 200 based on a incoming parameter. To illustrate I could have
Start = 1, End = 300
Start = 301, End = 600
Start = 601, End = 900
Start = 1201, End = 1500
Start = 1501, End = 1800
Because I have this jump I cannot use the above loop to create an instance of ShipmentInformation and take the first and last item in orderedData to use their data to populate that instance.
I would like some way of identifying a jump by 300 or 200 and creating an instance of ShipmentInformation to add to FinalResults where the data is sequnetial.
Using the above example I would have 2 instances of ShipmentInformation with a Start of 1 and an End of 900 and another with a Start of 1201 and End of 1800
Try the following:
private static IEnumerable<ShipmentInformation> Compress(IEnumerable<ShipmentInformation> shipments)
{
var orderedData = shipments.OrderBy(s => s.OuterNo).ThenBy(s => s.Start);
using (var enumerator = orderedData.GetEnumerator())
{
ShipmentInformation compressed = null;
while (enumerator.MoveNext())
{
var current = enumerator.Current;
if (compressed == null)
{
compressed = current;
continue;
}
if (compressed.OuterNo != current.OuterNo || compressed.End < current.Start - 1)
{
yield return compressed;
compressed = current;
continue;
}
compressed.End = current.End;
}
if (compressed != null)
{
yield return compressed;
}
}
}
Useable like so:
var finalResults = Results.SelectMany(Compress).ToList();
If you want something that probably has terrible performance and is impossible to understand, but only uses out-of-the box LINQ, I think this might do it.
var orderedData = item.OrderBy(x => x.Start);
orderedData
.SelectMany(x =>
Enumerable
.Range(x.Start, 1 + x.End - x.Start)
.Select(n => new { time = n, info = x))
.Select((x, i) => new { index = i, time = x.time, info = x.info } )
.GroupBy(t => t.time - t.info)
.Select(g => new ShipmentInformation {
OuterNo = g.First().Key,
Start = g.First().Start(),
End = g.Last().End });
My brain hurts.
(Edit for clarity: this just replaces what goes inside your foreach loop. You can make it even more horrible by putting this inside a Select statement to replace the foreach loop, like in rich's answer.)
How about this?
List<ShipmentInfo> si = new List<ShipmentInfo>();
si.Add(new ShipmentInfo(orderedData.First()));
for (int index = 1; index < orderedData.Count(); ++index)
{
if (orderedData.ElementAt(index).Start ==
(si.ElementAt(si.Count() - 1).End + 1))
{
si[si.Count() - 1].End = orderedData.ElementAt(index).End;
}
else
{
si.Add(new ShipmentInfo(orderedData.ElementAt(index)));
}
}
FinalResults.AddRange(si);
Another LINQ solution would be to use the Except extension method.
EDIT: Rewritten in C#, includes composing the missing points back into Ranges:
class Program
{
static void Main(string[] args)
{
Range[] l_ranges = new Range[] {
new Range() { Start = 10, End = 19 },
new Range() { Start = 20, End = 29 },
new Range() { Start = 40, End = 49 },
new Range() { Start = 50, End = 59 }
};
var l_flattenedRanges =
from l_range in l_ranges
from l_point in Enumerable.Range(l_range.Start, 1 + l_range.End - l_range.Start)
select l_point;
var l_min = 0;
var l_max = l_flattenedRanges.Max();
var l_allPoints =
Enumerable.Range(l_min, 1 + l_max - l_min);
var l_missingPoints =
l_allPoints.Except(l_flattenedRanges);
var l_lastRange = new Range() { Start = l_missingPoints.Min(), End = l_missingPoints.Min() };
var l_missingRanges = new List<Range>();
l_missingPoints.ToList<int>().ForEach(delegate(int i)
{
if (i > l_lastRange.End + 1)
{
l_missingRanges.Add(l_lastRange);
l_lastRange = new Range() { Start = i, End = i };
}
else
{
l_lastRange.End = i;
}
});
l_missingRanges.Add(l_lastRange);
foreach (Range l_missingRange in l_missingRanges) {
Console.WriteLine("Start = " + l_missingRange.Start + " End = " + l_missingRange.End);
}
Console.ReadKey(true);
}
}
class Range
{
public int Start { get; set; }
public int End { get; set; }
}

finding a member property of an item in an array

I've passed in the whole sale object into this function. In that sale object, there are many childs e.g. saleOrderItem, Payment, User...
sale.payment is an array
Question:
1) How do I get the CodeNo from the `sale.payment' object? (as payment is an array)
2) How to get the sale.payment.CourseByTutor.TutorId (as payment is an array)
public static object GetSalesDataBySaleOrderID(SaleOrder sale)
{
return sale.saleOrderItem
.Where(s => s != null)
.Select(s => new {
Id = s.Id,
Username = sale.User.GetSingleUserById(s.UserId).Name,
Amount = s.Amount,
CodeNo = s.SaleOrder.payment.First().CodeNo,
TutorName = sale.User.GetSingleUserById(s.SaleOrder.payment.FirstOrDefault().CourseByTutor.TutorId).Name,
})
.ToList();
}
Here is how i bind the value to the object
private void SaveValueToObject()
{
saleOrder.UserId = UserInfo.Id;
saleOrder.Date = DateTime.Now;
for (int i = 0; i < dgSale.Rows.Count; i++)
{
SaleOrderItem SaleItem = new SaleOrderItem();
SaleItem.InventoryTypeId = Convert.ToInt32(dgSale.Rows[i].Cells["inventoryTypeId"].Value);
SaleItem.InventoryOrCourseId = Convert.ToInt32(dgSale.Rows[i].Cells["inventoryId"].Value);
SaleItem.Qty = Convert.ToInt32(dgSale.Rows[i].Cells["qty"].Value);
SaleItem.Amount = Convert.ToDecimal(dgSale.Rows[i].Cells["total"].Value);
SaleItem.UserId = Convert.ToInt32(dgSale.Rows[i].Cells["userId"].Value);
SaleItem.Discount = Convert.ToDecimal(dgSale.Rows[i].Cells["discount"].Value);
SaleItem.Remarks = (dgSale.Rows[i].Cells["remark"].Value == null) ? "" : dgSale.Rows[i].Cells["remark"].Value.ToString();
SaleItem.Status = (int)SaleOrderStatus.Active;
saleOrder.saleOrderItem[i] = SaleItem;
Payment p = new Payment();
p.PayType = Convert.ToInt32(dgSale.Rows[i].Cells["payType"].Value);
p.Code = (int)PaymentCode.RCT; // For Receipt prefix
p.CodeNo = p.GetNewReceiptNo(p.Code); //Check if it is receipt, if yes, Get last Receipt No + 1
p.UserId = (txtUserId.Text == string.Empty) ? 0 : Convert.ToInt32(txtUserId.Text);
p.Amount = Convert.ToDecimal(dgSale.Rows[i].Cells["total"].Value);
p.Remark = (dgSale.Rows[i].Cells["remark"].Value == null) ? "" : dgSale.Rows[i].Cells["remark"].Value.ToString();
p.PaymentMethodId = saleOrder.PaymentMethodId;
p.DateIssue = saleOrder.Date;
p.CourseByTutor.TutorId = Convert.ToInt32(dgSale.Rows[i].Cells["tutorId"].Value);
saleOrder.payment[i] = p;
}
}
I have a workaround and solved this question by adding the desired properties e.g. TutorId in the sale.saleOrderItem class. Thus making the direct access to the sale.SaleOrderItem.TutorId.
This sound stupid but it works.

Categories