Parsing xml and selecting just specific positions from an array - c#

I'm parsing an xml document, that is like this:
<?xml version="1.0" encoding="UTF-8" ?>
....
<maj>true</maj>
<data>
<c>2</c>
<t>0</t>
<r>168</r>
<r>La rentrée Auchan</r>
<r>0</r>
<r>2012-08-21 00:00:00</r>
<r>2012-08-28 00:00:00</r>
<r>56</r>
<r>VL</r>
<c>2</c>
<t>1</t>
...
</data>
I want to get what there is inside the array "r", but only the first position 1 the position 5 and 6, and only where t=0
I've tried to work like this, I have a listbox that bind the data :
XDocument XMLtxt = JsonConvert.DeserializeXNode(e.Result);
listClients.ItemsSource =
from c in XMLtxt.Descendants()
select new JsonB()
{
t=c.Element("t").Value.Where(x=>(int) x==0),
r1=c.Element("r").Select(..
}
the jsonB :
public class JsonB
{
public int c { get; set; }
public int t { get; set; }
public string r1 { get; set; }
public int r5 { get; set; }
public string r6 { get; set; }
public object[] r { get; set; }
}
I really need help, thank you

The XML is a bit ill-structured, so you will have to fix this first with your code.. For starters, in a simple way you can sequentially read/parse the contents so that the structure of the record is clear, and then filter them:
prepare a list of JsonB objects - name it i.e. 'allRecords'
prepare a variable of type JsonB - name it i.e. 'lastRecord'
prepare a variable of type int - name it i.e. 'numberOfRs'
get the <data> tag
loop over all of its direct children, and for each child:
check the name of the child
if it is <c>:
create new JsobB and put it into lastRecord
reset the numberOfRs to zero
add the lastRecord to the allRecords list
read the c value and put it into lastRecord.c
if it is <t>:
read the value and put it into lastRecord.t
if it is <r>:
add 1 to the numberOfRs
if numberOfRs is 1, 5 or 6:
read the value and put it into lastRecord.r1 or r5 or r6
this way, you will have a list allRecords with pretty objects, and you can simply .Where(item => item.t ==0) on it.
However, you may notice it to be very 'wasteful' if many of such objects are to be ignored. Then, you could adjust the sequential parser to filter then on-the-fly and thus behave like this
prepare a list of JsonB objects - name it i.e. 'allRecords'
prepare a variable of type JsonB - name it i.e. 'lastRecord'
prepare a variable of type int - name it i.e. 'numberOfRs'
prepare a variable of type bool - name it i.e. 'isInteresting', preset it to false
get the <data> tag
loop over all of its direct children, and for each child:
check the name of the child
if it is <c>:
if isInteresting is true
add the lastRecord to the allRecords list
create new JsobB and put it into lastRecord
reset the numberOfRs to zero
add the lastRecord to the allRecords list reset the isInteresting to false
read the c value and put it into lastRecord.c
if it is <t>:
read the value and put it into lastRecord.t
if it was zero, set the isInteresting to true
if it is <r>:
add 1 to the numberOfRs
if numberOfRs is 1, 5 or 6:
read the value and put it into lastRecord.r1 or r5 or r6
if isInteresting is true
add the lastRecord to the allRecords list
This way, you will end up with a list that is already filtered and all not interesting items will be GC'ed in the meantime. Please note that the 'isinteresting - add to list' is done twice: once before creatig new JsonB, and then also in the final step when all children has been read. If you forget about the check-add after the loop - you may sometimes accidentially skip/ignore the last record.

Related

How to Pivot a List<T> and assign to a GridView without the use of DataTable?

I am currently preparing my Application to transition over to MVC and in doing so have replaced all SQL statements with LINQ (EF) and removing all Datasets/DataTables, replacing them with strongly typed Lists.
I am stuck on one scenario where I need to pivot a strongly typed List<T> , after I pivot (number of columns produced vary) I am attempting to re-assign the results back to the GridView, keeping in mind that I don't want to use a DataTable.
I have looked at various examples where people are attempting to use ExpandoObject but I can't get it to work and continue to get this error:
The data source for GridView with id 'GridReport' did not have any properties or attributes from which to generate columns. Ensure that your data source has content.
The alternative would be to create some kind of class dynamically with properties getter and setter, would this be the right approach?
Given that eventually I will discard GridView too in MVC (controls not supported) I am now just thinking to maybe create an output just using HTML table? Since all I am doing is outputting the display and not using the GridView for any other purpose.
Some guidance and code example would help for the right scenario.
My List <T> looks like this (shortened for simplicity) and I pivot on ticker_id using a GroupBy. Am I able to return the property names from the Linq query too? if so how?:
public class CorporationCompare
{
public int ticker_id { get; set; }
public string tickerSymbol { get; set; }
public decimal? price { get; set; }
}
//pivot
var query = (from item in lstCompareCorp
let key = new { ticker_id = item.ticker_id }
group new { tickerSymbol = item.tickerSymbol, price = item.price } by key)
.ToList();
Before Pivot:
ticker_id tickerSymbol price
1 GOOG 123.45
208 AAPL 543.21
After Pivot:
ticker_id 1 208
tickerSymbol GOOG AAPL
price 123.45 543.21

How to use AutonumberAttribute.getNextNumber()?

When I use the AutonumberAttribute.getNextNumber(), it gives me the next number of the sequence but it also make the next number to change.
IE if I call 2 time in a row:
nextNumber = AutoNumberAttribute.GetNextNumber(ARLetteringPiece.Cache, LetteringPiece, numbering, DateTime.Now);
first time i'll get "0000001"
second time i'll get "0000002"
I want to be able to know what the next number will be without modifying it's next value.
Is there a way to achieve this ?
Thanks a lot
Edit to answer the comments :
I have a custom table, my UI key is generated with Autonumbering, and I need to put this key in the lines of my other tables to "bind" them to my custom table. So I need to know what will be the autogenerated number.
It depends on the relationship between your DACs (tables).
You can solve this by using the PXDBChildIdentity in the fields of all the tables that need to store the new key.
For example, if your DAC's autonumber field is of type integer and is called MyDAC.MyAutonumberField.
You can add the attribute to all fields in your other DACs that need to store the value like this:
[PXDBInt()]
[PXDBChildIdentity(typeof(MyDAC.myAutonumberField))]
public virtual int? MyDACID { get; set; }
If the other DACs are "children" of your custom DAC you should use the PXParent attribute in all the child DACs on the field that references their parent like this:
[PXDBInt(IsKey = true)]
[PXDBDefault(typeof(MyDAC.myAutonumberField))]
[PXParent(typeof(Select<MyDAC,
Where<MyDAC.myAutonumberField,
Equal<Current<myAutonumberField>>>>))]
public virtual int? MyParentDacID { get; set; }
I managed to do it in another way : First I save my "header", then I update the lines with the value autogenerated for my header and then I save it again.
public static void createLettering(List<ARRegister> lines)
{
// We build a new LELettering piece
Lettrage graph = CreateInstance<Lettrage>();
LELettering piece = new LELettering();
piece.Status = ListStatus._OPEN;
piece.LetteringDateTime = DateTime.Now;
piece = graph.ARLetteringPiece.Insert(piece);
// We fill the checked lines with the autonumber of the piece
bool lineUpdated = false;
foreach (ARRegister line in lines)
{
if (line.Selected.Value)
{
if (!lineUpdated)
{
piece.BranchID = line.BranchID;
piece.AccountID = line.CustomerID;
piece = graph.ARLetteringPiece.Update(piece);
graph.Actions.PressSave();
}
line.GetExtension<ARRegisterLeExt>().LettrageCD = graph.ARLetteringPiece.Current.LetteringCD;
graph.ARlines.Update(line);
lineUpdated = true;
}
}
// If there are lines in our piece, we save it
// It saves our lettering piece and our modifications on the ARLines
if (lineUpdated)
{
graph.Actions.PressSave();
}
}

asp:gridview with a list as datasource, which also has a dictionary

I have a table with closing codes, for example:
Code Description
CL1 Reason 1
CL2 Reason 2
AF1 After 1 period
AF2 After 2 periods
Also a table with orders. Orders will be imported once a week and the table has, besides the other columns, a column holding the batch date and one holding the closing code. This last one can be NULL when the order isn’t closed or has one of the codes from the first given table.
I want to have a gridview which list per batch the total number of orders, the number of closed orders and per reason the number of orders involved.
Already made a class like this:
public class BatchSales
{
public DateTime BatchDate { get; set; }
public int BatchCount { get; set; }
public int TotalClosed { get; set; }
public Dictionary<string, int> Counters { get; set; }
}
And a method which returns a List of BatchSales.
Defined an asp:gridview in my aspx-page, with AutoGenerateColumns=false. I like to get this filled with 5 columns (batch date, count, closed, CL1, CL2, AF1 and AF2) and per row the relevant data.
In my code behind already added the first 3. My problem is adding the columns based on the dictionary. I’ve the closing codes read in a list and doing this:
foreach (var item in reasons)
{
BoundField bf = new BoundField();
bf.HeaderText = item.Description;
bf.DataField = "xxxx";
bf.DataFormatString = "{0:n0}";
bf.HeaderStyle.VerticalAlign = VerticalAlign.Top;
bf.ItemStyle.VerticalAlign = VerticalAlign.Top;
bf.ItemStyle.Wrap = false;
gvBatch.Columns.Add(bf);
}
What do I need to define for xxxx to get the value from the dictionary? Or isn’t this the right approach?
What you're wanting is more of a pivot grid. That aside, you need either an item template in the dictionary column that shows your dictionary data as rows (not ideal) or what I would do in this case is just have a button in that column that said something like "Show Details" and either have a modal window pop up with the list of counts or send it to a details page with the list of counts.

mongodb C# error on first Push

I've a Parent Entity that has a property of list of Child Entities. Initially on Insert I don't have values for the child entities.
But when I try to Update(by calling push) the document with Child Entities it fails.
This works when I insert a dummy child entity value to the Initial Add .
This is because the embedded document refers to null .
public class ParentDocument : Entity
{
public string prop1 { get; set; }
public List<EmbeddedDocument> EmbeddedDocuments { get; set; }
}
public class EmbeddedDocument
{
public string prop2{ get; set; }
}
The parent is saved First
_collection.InsertOne(new ParentDocument(){prop1 ="value"});
and later when I Update the document
var builder = Builders<ParentDocument>.Update;
var updateDefintion = builder.Push(x => x.EmbeddedDocuments ,new EmbeddedDocument() { prop2= "value2" });
_collection.UpdateManyAsync(x=>x.Id==ParentDocumentId, updateDefinition)
error occurs "A write operation resulted in an error mongodb"
But this push works if I have already inserted Embedded Document(s) in the List on first insert.
I think that is because of that the EmbeddedDocuments property is Inserted as null the push doesn't work.
I also tried passing empty List to intial Insert,but not helped.
One Idea would be to check if the count of List of Embedded documents is zero and call
Builder.set(x=>x.EmbeddedDocuments ,new List<EmbeddedDocument>(){ item1 });
But this will cost a query , which I don't want to.
Is there any other solution?
Thanks in Advance
To Hazard a guess, it's because the "array" field in the database is null after the insert. You either need to make the initial value in the database an empty array, or you need to make it not-present. You can either:
use the [BsonIgnoreIfDefault] attribute on your list field to not store nulls,
Initialize your list field to an empty list to store an empty array
This can be reproduced in the shell very easily:
> db.so.insert({x:1, y: null})
> db.so.update({x:1}, {$push: { y: "funny" }})
This will error. However, if you remove y from the insertion or change it to an empty array, the update will succeed.

Remove a property/column from a generic list

Due to some reason I cannot change the query so I have to do this in C#.
I have a class:
public class myClass
{
int id { get; set; }
string name { get; set; }
DateTime sDate { get; set; }
bool status { get; set; }
}
The data I am getting is fetched in this list. Now what I want is to remove those properties from a list that has null values. I may sound insane but you read it right. I thought of creating another list with only the selected properties, but any of the above properties can be null. So I have to devise a mechanism to filter my list based on this.
For more clarity consider the following example.
List<myClass> lstClass = some data source.
After getting the data the generic list(lstClass) looks like this.Consider the result set in a table:
Id Name Sdate status
1 a null null
2 b null null
3 c null false
Can i some how make my list look like this after removing the property sdate.
So the new list that I want to create should have only three properties.
Id Name status
1 a null
2 b null
3 c false
Any ideas? Can I do this using Linq?
PS: This has nothing to do with presentation. I don’t have a grid where I am not able to hide columns that Is not what I am looking for.
Assuming you have a generic list of myClass instances, you can create an anonymous type with only the needed properties:
List<myClass> list = ...;
var reducedList = list.Select(e => new {e.id, e.name, e.status}).ToList();
// note: call to ToList() is optional
foreach (var item in reducedList)
{
Console.WriteLine(item.id + " " + item.name + " " + item.status);
//note: item does not have a property "sDate"
}
I'm not sure you should solve your issue in the Data, but rather it's a presentation problem.
In which control do you want to display it ? Let's say you display it in DataGrid with AutoGenerateColumns=True, then you can 1) loop on columns/properties 2) for each column/property see if all property values for all rows are null and if so set column's visibility to Collapsed.
If you generate your columns by yourself it's even simpler : only add columns when content is not null for all rows.
If your DB content is dynamic, you might want to bind each row's visibility to a property that would state wether all rows are null or not for that property. Depending on how generic you want your code to be, the code might be very different, and in case you want to have generic solution, using Reflection to retrieve/get/set properties might be of some use.

Categories