I need a verry especific format for each field of MyObject class
public class MyObject{
public Long Amount {get; set}
public Long FiscalAmount {get; set;}
// .... A lot more of fields
}
For example,
if MyObject.Amount is 5000 the expected result is 00005000.
if MyObject.FiscalAmount is 23 the expected result is 000023
In order to accomplished this, I have defined an XML file:
<FieldDescriptionXML>
<FielDefinition>
<Name>Amount</Name>
<FillWith>0</FillWith>
<Lenght>8</Lenght>
</FielDefinition>
<FielDefinition>
<Name>FiscalAmount</Name>
<FillWith>0</FillWith>
<Lenght>6</Lenght>
</FielDefinition>
.... A lot more of fields
<FieldDescriptionXML>
Then I use the following code to get MyObject fields with the desired output
MyObject myObject = new MyObject();
myObject.Amount = 5000;
...
// Gets the xml definition
// I deserialize the previous XML file and name it FieldDescription
List<FieldDescription> fieldDescriptionList = DeserializeXML(XMLFilePath);
FieldDescription fieldDescription = fieldDescriptionList.Find(x => x.Name == "Amount");
// Apply the field definition and returns a string.
// For this I use a private method called ApplyXMLFielDefinition
// where I got how many spaces the result should be filled
string result = ApplyXMLFielDefinition(myObject.Amount,fieldDescription);
Console.Writeline(result) // prints 00005000
// Now same code for MyObject.FiscalAmount
As you see, I got the desired output, but I had to do it one by one repeating the code.
Is there any other other better approached you can share?, thanks.
Environment: C# 4.0
If I am reading your question correctly you will have a list of elements you want populated from a large xml collection. Have you tried LinqToXml
var x = (from target in xmlDoc.Decendants("FielDefinition")
select (int) target.Element("FillWith").value()
where target.Element("Name").Value.tolower() == "amount")).ToList();
That will return a list<int>
Related
I have a JSON result with the following structure:
{
"property1":1,
"property2":[[1,"A"],[2,"B"],[3,"C"],...] // Possible to get >10000 values
}
Using the above JSON data format, I am only interested to get the array values from the property2 which contains an array of array values and convert it to data table.
The above JSON result is coming from an external WEB API and here is what I have currently:
var jsonResponse = API.RetrieveData();
JObject json = JObject.Parse(jsonResponse);
JToken[] A = json["property2"].ToArray();
Logically, I can loop on the elements of Array [] A column by column and add it to the predesigned data table. My problem is that, upon using this, the performance will be affected as in most cases, the data that will be retrieved from the API is > 10000 values.
Is there any specific way to convert this kind of JSON Format to DataTable in c# with the most efficient way?
Thank you in advance.
I have Better and Fast approach for You
Step 1
Create a class that is similar to json structure
public class JsonClass
{
public string property1 { get ; set; }
public List<Dictionary<int,string>> property2 { get ; set; }
}
Step 2
Use Newtonsoft and deserialize json input to json match class
JsonClass jsonClass = JsonConvert.DeserializeObject<JsonClass>(jsonInputString);
Step 3
if you are using WPF just use
datatable.ItemSource = jsonClass ;
if you are using Winform then use BindingSource Component
BindingSource binding = new BindingSource();
binding.DataSource = jsonClass;
datatable.DataSource = binding;
Result might be
property1 | property2
---------------------------------------
"A" | Collection
Good luck
I have a table on my Database where, aside from other columns (one of which is a UniqueIdentifier) I also have one column where I have a JSON array string with values like this (formatted):
[
{
"AttributeId": "fe153d69-8ac1-6e0c-8793-ff0000804eb3",
"AttributeValueId": "64163d69-8ac1-6e0c-8793-ff0000804eb3"
},
{
"AttributeId": "00163d69-8ac1-6e0c-8793-ff0000804eb3",
"AttributeValueId": "67163d69-8ac1-6e0c-8793-ff0000804eb3"
}
]
I then have this AttributeValuePair class which will allow me to read this data on code:
public class AttributeValuePair
{
public AttributeValuePair();
public Guid AttributeId { get; set; }
public Guid AttributeValueId { get; set; }
}
Whenever I get a list of items from this table, I want to be able to filter the resulting array based on only one AttributeValueId and get only the items where this is a match, independently of the value of any other attributes.
Since that on code, to read these attribute collection I must have a List<AttributeValuePair>, how in LINQ can I get the items where a particular AttributeValueId is present?
List<AttributeValuePair> attributeValuePairs = serializer.Deserialize<List<AttributeValuePair>>(item.Variant);
I've been lost at it for two hours already and can't seem to find an escape from this one.
EDIT
Being more clear about the problem, what I'm trying to do is, from a List<ProductVariation>, get the possible values for the attribute "Portions", when the attribute "Days" is the specified value. I'm having a lot of trouble using the serializer to build the LINQ statement.
//This code is wrong, I know, but I'm trying to show what I want
result = model.ProductVariations.Find(x, new {serializer.Deserialize<List<AttributeValuePair>>(item.Variant).Where(valuePair => valuePair.AttributeId == attributeId)});
Can you try
attributeValuePairs.Where(valuePair => valuePair.AttributeId == new Guid("SomeValue"));
The answer to this question was actually a lot simpler than previously expected:
public string SelectedVariation(string mealsAttribute, string portionsAttribute, string product)
{
Guid productId = new Guid(product);
CatalogManager catalogManager = CatalogManager.GetManager();
EcommerceManager ecommerceManager = EcommerceManager.GetManager();
RegisterOrderAccountFormModel model = new RegisterOrderAccountFormModel();
model.Product = catalogManager.GetProduct(productId);
List<ProductVariation> productVariationsCollection = catalogManager.GetProductVariations(productId).ToList();
//This is the really interesting part for the answer:
return productVariationsCollection.Where(x => x.Variant.ToLower().Contains(mealsAttribute.ToLower()) && x.Variant.ToLower().Contains(portionsAttribute.ToLower())).FirstOrDefault().Id.ToString();
}
XML Snippet
<GameList>
<Game>
<GameDefinitiongameID>{1b2e4ff7-ddd3-4fe3-9fdf-6b2ee240d18c}</GameDefinitiongameID>
<WMID>{01bc5c01-923d-4efb-bba6-49e93b2694ab}</WMID>
<VersionNumberversionNumber>1.0.0.0</VersionNumberversionNumber>
<Title>JamesBond007:Nightfire</Title>
<GameExecutablepath>\easupport\go_ez.exe</GameExecutablepath>
<GameExecutablepath>\easupport\jamesbond007nightfire_code.exe</GameExecutablepath>
<GameExecutablepath>\easupport\jamesbond007nightfire_ereg.exe</GameExecutablepath>
<GameExecutablepath>\easupport\jamesbond007nightfire_ez.exe</GameExecutablepath>
<GameExecutablepath>jamesbond007nightfire_uninst.exe</GameExecutablepath>
<GameExecutablepath>unwise.exe</GameExecutablepath>
<RatingratingID>{CEC5DB5A-B4C9-4809-96C6-39CE715E4790}</RatingratingID>
<ratingSystemID>{36798944-B235-48ac-BF21-E25671F597EE}</ratingSystemID>
<DescriptordescriptorID>{F110F831-9412-40c9-860A-B489407ED374}</DescriptordescriptorID>
<RatingratingID>{18CD34B7-7AA3-42b9-A303-5A729B2FF228}</RatingratingID>
<ratingSystemID>{768BD93D-63BE-46A9-8994-0B53C4B5248F}</ratingSystemID>
<DescriptordescriptorID>{B54162A2-F67F-46dc-9ED5-F6067520EC94}</DescriptordescriptorID>
<DescriptordescriptorID>{BE562A5F-2A80-4c28-9752-74C696E2ABAF}</DescriptordescriptorID>
</Game>
and so on.
I used the following to query this file
Dim members = From m In GameXml.Element("GameList").Elements("Game")
Where m.Element("Title").Value.ToLower.Contains(Name) = True
Select m.Descendants
"Name" is the variable containing the search string.
Now, how to I get all the info (as array of strings or any other parse-able format) from the "members" variable.
I am new to XML and LINQ.
I am OK with both C# and VB.Net.
If you don't know what exact properties it has you can do this:
dynamic members = from m In GameXml.Element("GameList").Elements("Game")
where m.Element("Title").Value.ToLower.Contains(Name) = True
select m;
now you can use: members.ratingSystemID
But if you know the properties you can create a class like:
public class Game{
public string Title{set; get; }
public string Name {get; set;}
.
.
.
}
and then:
List<Game> members = from m In GameXml.Element("GameList").Elements("Game")
where m.Element("Title").Value.ToLower.Contains(Name) = True
select new {Title = m.Title, Name = m.Name, ...};
so you can use it like Members[0].Title
Assuming you want to get Game node, you're so close:
Dim members = From m In GameXml.Element("GameList").Elements("Game")
Where m.Element("Title").Value.ToLower.Contains(Name) = True
Select m.Descendants("Game")
or (C#):
var members = GameXml.Descendants("Game")
.Where(g=>g.Element("Title").Value.ToLower().Contains("Whatever"));
i'm coming from PHP to C#, so please excuse some of my terminology.
Currently i'm working on a small project that requires multiple profiles to be stored in one single file, so i decided to use XML, because INI files (usually my go to guy for text based stuff) are not really supported by C#. At least not in a satisfying way.
Here the basic structure of my XML file:
<profile name="FooBar">
<btnA pressed="actionA" released="actionB" />
<btnB pressed="actionX" released="actionY" />
...
</profile>
<profile name="XYZ">
<btnA pressed="actionA" released="actionB" />
<btnB pressed="actionX" released="actionY" />
...
</profile>
In PHP i would generate an associative array with the following structure:
<?php
foo = array(
'FooBar' => array(
'btnA_pressed' => 'actionA',
'btnA_released' => 'actionB'
// ...
),
'XYZ' => array(
// ...
)
);
EDIT START
Application Class Structure:
Settings (Contains all profiles and a reference to the current profile)
Profile (See below)
The Profile class:
public class Profile
{
private string _name;
public string Name
{
get { return this._name; }
set { this._name = value;}
}
private string _btnA_pressed;
public string BtnA_Pressed { get; set; }
// and so on...
public Profile(var data) { // arg is a placeholder
// associate the data with the properties
}
}
In short, the Settings class holds all profiles and a reference to the selected profile. Access to the profile goes over Settings.CurrentProfile.propertie_Name()
EDIT END
The question is now, how do i achieve the same or a similar thing in C#? Or are there better methods of achieving the same thing?
Thanks for your help in advance!
XML structures can be manipulated very easily with LINQ2XML without the need of typed models (classes).
Reading XML file containing many profile nodes (and i assume your XML file is correct and has one root node), can look like this:
// read existing XML structure
var xml = XDocument.Load("d:\\temp\\xml\\profile.xml");
// take all profile elements
var profiles = xml.Root.Elements("profile").ToList();
foreach (var profile in profiles)
{
Console.WriteLine(profile.Attribute("name").Value);
// find all button elements
var buttons = profile
.Elements()
.Where (e => e.Name.ToString().StartsWith("btn"));
// list elements
foreach (var button in buttons)
{
// tag name
var name = button.Name.ToString();
// attributes
var pressed = button.Attribute("pressed").Value;
var released = button.Attribute("released").Value;
Console.WriteLine(String.Format("{0} - P'{1}' - R'{2}'", name, pressed, released));
}
}
The output is:
FooBar
btnA - P'actionA' - R'actionB'
btnB - P'actionX' - R'actionY'
XYZ
btnA - P'actionA' - R'actionB'
btnB - P'actionX' - R'actionY'
Reading a single profile XML structure from a string and then creating a new one can look like this:
var xmlCode = #"<profile name=""FooBar""><btnA pressed=""actionA"" released=""actionB"" /><btnB pressed=""actionX"" released=""actionY"" /></profile>";
try
{
// read existing XML structure
var xml = XDocument.Parse(xmlCode); // XDocument.Load("c:\\path\\to\\file.xml");
// find all button elements
var buttons = xml.Root
.Elements()
.Where (e => e.Name.ToString().StartsWith("btn"));
// list elements
foreach (var button in buttons)
{
// tag name
var name = button.Name.ToString();
// attributes
var pressed = button.Attribute("pressed").Value;
var released = button.Attribute("released").Value;
Console.WriteLine(String.Format("{0} - P'{1}' - R'{2}'", name, pressed, released));
}
// create xml
// root element
var newXml = new XElement("profile", new XAttribute("name", "FooBaz"),
new XElement("btnA",
new XAttribute("pressed", "actionX"),
new XAttribute("released", "actionXR")),
new XElement("btnB",
new XAttribute("pressed", "actionZ"),
new XAttribute("released", "actionZR")));
Console.WriteLine(newXml.ToString());
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
}
The output is:
btnA - P'actionA' - R'actionB'
btnB - P'actionX' - R'actionY'
<profile name="FooBaz">
<btnA pressed="actionX" released="actionXR" />
<btnB pressed="actionZ" released="actionZR" />
</profile>
You can use LINQ2XML to read the data and fill a list of objects of your Profile type like this:
// read existing XML structure
var xml = XDocument.Load("d:\\temp\\xml\\profile.xml");
// take all profile elements
var profiles = xml.Root.Elements("profile").ToList();
var listOfProfiles = new List<Profile>();
foreach (var profile in profiles)
{
var profileObject = new Profile("");
profileObject.Name = profile.Attribute("name").Value;
// find all button elements
var buttons = profile
.Elements()
.Where (e => e.Name.ToString().StartsWith("btn"));
// list elements
foreach (var button in buttons)
{
// attributes
var pressed = button.Attribute("pressed").Value;
var released = button.Attribute("released").Value;
profileObject.BtnA_Pressed = pressed;
}
listOfProfiles.Add(profileObject);
}
You can also use XML serialization - you need to describe your XML structure as a class (typed model) and deserialize (read XML file into your class) resp. serialize (write your XML structure to a file). A generic implementation of the methods for serialization resp. deserialization can look like this:
public void SerializeModel<T>(string fqfn, T entity)
{
var xmls = new XmlSerializer(entity.GetType());
var writer = new StreamWriter(fqfn);
xmls.Serialize(writer, entity);
writer.Close();
}
public T DeserializeModel<T>(string fqfn)
{
var fs = new FileStream(fqfn, FileMode.Open);
var xmls = new XmlSerializer(typeof(T));
var r = (T) xmls.Deserialize(fs);
fs.Close();
return r;
}
The typed model that describes your Profile class and the lists contained within, looks like this (note the usage of the different XML serialization attributes):
public class Profiles
{
[XmlElement(ElementName="Profile")]
public List<Profile> Profile { get; set; }
}
public class Profile
{
[XmlArray(ElementName="Buttons")]
public List<Button> Buttons { get; set; }
[XmlAttribute]
public String Name;
}
public class Button
{
[XmlAttribute]
public String Pressed { get; set; }
[XmlAttribute]
public String Released;
}
Creation of an XML file:
var profiles = new Profiles();
var profileA = new Profile();
var profileB = new Profile();
var buttonA = new Button();
var buttonB = new Button();
profileA.Buttons = new List<Button>();
profileB.Buttons = new List<Button>();
profiles.Profile = new List<Profile>();
profileA.Name = "Profile A";
profileB.Name = "Profile B";
buttonA.Pressed = "Pressed A";
buttonA.Released = "Release A";
buttonB.Pressed = "Pressed B";
buttonB.Released = "Release B";
profileA.Buttons.Add(buttonA);
profileB.Buttons.Add(buttonB);
profiles.Profile.Add(profileA);
profiles.Profile.Add(profileB);
var xmlFile = "d:\\temp\\xml\\profile_model.xml";
SerializeModel<Profiles>(xmlFile, profiles);
The new XML file looks like this (note, the structure was slightly modified because of the way XML serialization in .NET handles arrays/lists):
<?xml version="1.0" encoding="utf-8"?>
<Profiles xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Profile Name="Profile A">
<Buttons>
<Button Released="Release A" Pressed="Pressed A" />
</Buttons>
</Profile>
<Profile Name="Profile B">
<Buttons>
<Button Released="Release B" Pressed="Pressed B" />
</Buttons>
</Profile>
</Profiles>
The file can be then read like this:
var input = DeserializeModel<Profiles>(xmlFile);
foreach (var profile in input.Profile)
{
var b = profile.Buttons.First();
Console.WriteLine(String.Format("{0} - {1} - {2}", profile.Name, b.Pressed, b.Released));
}
The output is as expected:
Profile A - Pressed A - Release A
Profile B - Pressed B - Release B
Both approaches have advantages and disadvantages.
IMO the answer to your question (changed a bit) Is XML the correct approach for saving structured data to a file? is - definitely yes! Nowadays XML is one of the standards for representing / manipulating / exchanging structured data and data generally (data kept in a string). As someone already mentioned INI files were not really meant to represent complex nested structures.
In contrast to PHP where you might be used to doing a lot of arrays and magic-string based stuff, C# is a Statically Typed language where it's usually recommended to create a proper, formally defined, structured Data Model which allows you to manipulate the Data you're dealing with in a strongly typed manner.
This means, for example, that if you're dealing with personal information related data, and you need to deal with the concepts of last name, first name, and age you will want to create a class containing these pieces of data in the form of Properties, like so:
public class Person
{
public string LastName {get;set;}
public string FirstName {get;set;}
public int Age {get;set;}
//And so on...
}
Notice how each property has an adequate Data Type that allows you to constrain what values it can contain. For example, the fact that the Age property is of type int (integer numbers) automatically means you can never have something like "abc" inside it, and code like this:
var person = new Person();
person.Age = "abc";
will also produce a compile-time error, rather than blowing up at run time, or producing any sorts of inconsistencies in stored data.
Likewise, if your Person objects (in the real world data you're trying to model) have a relation to, say an Address, you're also going to create the Address class:
public class Address
{
public string Line1 {get;set;}
public string Line2 {get;set;}
public string City {get;set;}
//And so on...
}
And then model this Person -> Address relationship by creating an additional property in the Person class:
public class Person
{
//.. All of the above.
public Address Address {get;set;}
}
Which can be illustrated with a diagram like this:
This approach has the following advantages:
It provides Compile Time checking for correctness of the code. Compile-Time errors can be trapped (and need to be corrected) very early in the development cycle. For example, you can't do something like:
person.LatsName where the property name LastName is mispelled LatsName because the compiler "knows" there is no such property in the object model and thus you recieve a compile-time error rather than having the application crash at run-time.
It provides IDE support for features such as AutoComplete because the IDE "knows" the object model you're dealing with and thus it knows what properties/methods/events (Members) every class has, and what are the expected parameters and data types for each of these.
So, to answer the overarching question, once you created a proper object model, you can use .Net's built-in Serialization/Deserialization mechanisms to transform instances of classes in your object model (with actual values and properties) to a data format that can be stored in a file on disk, such as XML.
Assuming you have a class for profile with all the relevant fields/properties, you can do
Profile profile = new Profile();
profile.actionA = "actionA"; // or whatever you have
var file = new System.IO.StreamWriter(#"c:\temp\Profile_as_xml.xml");
var writer = new System.Xml.Serialization.XmlSerializer(typeof(Profile));
writer.Serialize(file, profile);
file.Close();
See http://msdn.microsoft.com/en-us/library/ms172873.aspx
I'm new to using Dynamic Objects in C#. I am reading a CSV file very similarly to the code found here: http://my.safaribooksonline.com/book/programming/csharp/9780321637208/csharp-4dot0-features/ch08lev1sec3
I can reference the data I need with a static name, however I can not find the correct syntax to reference using a dynamic name at run time.
For example I have:
var records = from r in myDynamicClass.Records select r;
foreach(dynamic rec in records)
{
Console.WriteLine(rec.SomeColumn);
}
And this works fine if you know the "SomeColumn" name. I would prefer to have a column name a a string and be able to make the same type refrence at run time.
Since one has to create the class which inherits from DynamicObject, simply add an indexer to the class to achieve one's result via strings.
The following example uses the same properties found in the book example, the properties which holds the individual line data that has the column names. Below is the indexer on that class to achieve the result:
public class myDynamicClassDataLine : System.Dynamic.DynamicObject
{
string[] _lineContent; // Actual line data
List<string> _headers; // Associated headers (properties)
public string this[string indexer]
{
get
{
string result = string.Empty;
int index = _headers.IndexOf(indexer);
if (index >= 0 && index < _lineContent.Length)
result = _lineContent[index];
return result;
}
}
}
Then access the data such as
var csv =
#",,SomeColumn,,,
ab,cd,ef,,,"; // Ef is the "SomeColumn"
var data = new myDynamicClass(csv); // This holds multiple myDynamicClassDataLine items
Console.WriteLine (data.OfType<dynamic>().First()["SomeColumn"]); // "ef" is the output.
You will need to use reflection. To get the names you would use:
List<string> columnNames = new List<string>(records.GetType().GetProperties().Select(i => i.Name));
You can then loop through your results and output the values for each column like so:
foreach(dynamic rec in records)
{
foreach (string prop in columnNames)
Console.Write(rec.GetType().GetProperty (prop).GetValue (rec, null));
}
Try this
string column = "SomeColumn";
var result = rec.GetType().GetProperty (column).GetValue (rec, null);