I have an XML file, I have a node and I read all ChildNodes. The name of the childNode match to a variable I have to set with the value of this childNode.
In the loop, I'd like set :
myvar1 to MyValue1
myvar2 to MyValue2
The C# Code :
protected string myvar1;
protected string myvar2;
The XML content look like this :
<parameters>
<myvar1>MyValue1</myvar1>
<myvar2>MyValue2</myvar2>
</parameters>
C# set variables :
foreach (var item in xmlParamInstallation.SelectNodes("parameters")[0].ChildNodes)
{
??????
}
Any idea ?
Thanks,
UPDATE 1:
the value "field" in the loop is null all the time.
public class ParametersTest
{
public string myvar1 { get; set; }
public string myvar2 {get; set;}
}
var type = typeof(ParametersTest);
foreach (XmlNode item in xmlParamInstallation.SelectNodes("parameters")[0].ChildNodes)
{
var field = type.GetField(item.LocalName);
field.SetValue(field, item.InnerText);
}
You can do it using Reflection:
var type = typeof(SomeClass);
var field = type.GetField(item.Name);
field.SetValue(null, item.InnerText);
RE: UPDATE 1
var parameters = new ParametersTest();
var type = parameters.GetType();
var s = #"<parameters>
<MyVar1>MyValue1</MyVar1>
<MyVar2>MyValue2</MyVar2>
</parameters>";
var xmlParamInstallation = new XmlDocument();
xmlParamInstallation.LoadXml(s);
foreach (XmlNode item in xmlParamInstallation.SelectNodes("parameters")[0].ChildNodes)
{
var field = type.GetProperty(item.LocalName);
field.SetValue(parameters, item.InnerText, null);
}
If you are seeking to assign variables based on the names of nodes in XML, you have at least a couple options:
Deserialize the XML structure into an object with corresponding member names
Populate the variables using reflection
Populate the variables using dynamic method calls/expression trees that know how to read the contents of the XML node into an object property.
All of these approaches suggest a more object-oriented approach to the problem then just populating a few variables, but it would be easy to create a lightweight structure with the appropriate members which is populated by reading the XML document.
You could also use a key-based collection (like a Dictionary<string, string>) to store the values if you are just looking to build a simple name/value collection from the source XML.
If you put the names and values in a dictionary, you can easily get the values by name:
Dictionary<string, string> parameters =
xmlParamInstallation.SelectNodes("parameters")[0].ChildNodes
.ToDictionary(n => n.Name, n => n.InnerText);
myvar1 = parameters["myvar1"];
myvar2 = parameters["myvar2"];
You could either do as "Default" said, or you could look into Reflection. By using the Type.GetMember(string) method you could find a member with the given name (the tag name in your XML) and set its value.
EDIT
Samich beat me, so I'll give him +1 - he's got sample code as well.
You can check out the XmlSerializer class
Related
I am looping through a List, and trying to instantiate one of the properties as a string, but it returns the type:
{Namespace.Collection}
If I put a break-point, I can see that it holds the value I need.
How can I make it return the value and not the type?
foreach (var PropertyName in ListName) {
string n = PropertyName.ToString();
}
UPDATE (added more of my code, as well as an attempt of implementing suggested solutions):
foreach (DataRow dr in ds.Tables[0].Rows) {
//PaidTrips is my ObservableCollection instance.
//PaidTrip is my holder class which it has been bound to.
PaidTrips.Add(new PaidTrip {
LicenseHolderID = dr[0].ToString(),
// adding more properties
});
List<PaidTrip> theseTrips = PaidTrips
.GroupBy(p => new { p.LicenseHolderID })
.Select(g => g.First())
.ToList();
foreach (PaidTrip PaidTrips in theseTrips) {
foreach (var LicenseHolderID in PaidTrips.GetType().GetProperties()) {
string n = LicenseHolderID.GetValue(PaidTrips).ToString();
// code to create PDF
}
gfx.DrawString(n, new XFont("Arial", 40, XFontStyle.Bold), ridelGreen, new XPoint(40, 350));
This is what I do with string n. But when the PDF is created, the string output is System.Action1[System.Action]`
What am I doing wrong?
You need to loop through the Property Types in your custom class, after looping through the list. First we need an additional loop - to loop through each ClassName Object in ListName list.
foreach (ClassName myObj in ListName)
{
foreach (var PropertyName in myObj.GetType().GetProperties())
{
string n = PropertyName.GetValue(myObj).ToString();
}
}
Then we need to loop the actual properties of the current loop ClassName object.
Then you pass the argument .GetValue (as you are now looping through the properties - the actual properties assigned, not the definition of properties).
After, you still need to specify what object you want the value of. So by passing myObj, you are specifying the ClassName->Property of the current loop of ListName.
EDIT:
List<Notes> myNotesNow = new List<Notes>();
myNotesNow.Add(new Notes
{
note1 = "Valuye"
// adding more properties
});
List<Notes> theseTrips = myNotesNow;
foreach (Notes PaidTrips in theseTrips)
{
foreach (var myVariable in PaidTrips.GetType().GetProperties())
{
string n = myVariable.GetValue(PaidTrips).ToString();
string forBreakPoint = "";
// code to create PDF
}
}
For your question - I guess that ListName is not of type string and so you get the expected behavior (see: https://learn.microsoft.com/en-us/dotnet/api/system.object.tostring?view=net-5.0#the-default-objecttostring-method)
In that case you can override the ToString() function of that object to return whatever you need like this:
public override string ToString()
{
return "whatever you want including class properties";
}
On another note, the general approach to variable naming in C# is camelCase and starts with lower case so I suggest to name your variables propertName instead of PropertyName and listName instead of ListName.
Moreover - naming variables for how they are implemented (ListName) is not a best practice as it binds them together, not allowing flexibility in case implementation changes (that comment is true only if it makes sense, as I dont see all the code)
Cheers
I have a lot of JSON format data into text file and format is like:
[{"ev":"AM","sym":"TMHC","v":1000,"av":74917,"op":18.92,"vw":19.1305,"o":19.13,"c":19.15,"h":19.15,"l":19.13,"a":19.143,"z":90,"n":1,"s":1549380300000,"e":1549380360000},{"ev":"AM","sym":"SPYG","v":7103,"av":184266,"op":35.27,"vw":35.3148,"o":35.3264,"c":35.34,"h":35.34,"l":35.3258,"a":35.3345,"z":710,"n":1,"s":1549380300000,"e":1549380360000},
{"ev":"AM","sym":"AAPL","v":73,"av":1866,"op":35.27,"vw":35.3148,"o":35.3264,"c":35.34,"h":35.34,"l":35.3258,"a":35.3345,"z":710,"n":1,"s":1549380300000,"e":1549380360000}]
So I need to find json element of particular symbol. Like if I use AAPL then it gives us all AAPL element data from txt file. Like
{"ev":"AM","sym":"AAPL","v":73,"av":1866,"op":35.27,"vw":35.3148,"o":35.3264,"c":35.34,"h":35.34,"l":35.3258,"a":35.3345,"z":710,"n":1,"s":1549380300000,"e":1549380360000}
So please can you help me to how should I make it ?
static void xPathUsing()
{
const string filePath = #"D:\Aggregate_Minute_AAPL.txt";
using (StreamReader r = new StreamReader(filePath))
{
string json = r.ReadToEnd();
}
}
As you need to run multiple operations on the data, the best way would be to read the data into memory once (or again whenever the data changes) and hold them in a way that supports fast querying. In order to find a row by the symbol, you could create a dictionary that holds the data.
The following samples use the widely used JSON.NET library for parsing the JSON.
First, you need to define a class that ressembles the schema of your JSON objects, e.g.:
class Row
{
[JsonProperty("sym")]
public string Symbol { get; set; }
public decimal vw { get; set; }
// ...
}
Please note that you can use the JsonProperty attribute in order to be able to assign different names to the properties of the class than in the JSON.
The following sample shows how to read the data from a file and how to convert it to a dictionary:
var input = File.ReadAllText("C:\\Temp\\abc.json");
var rows = JsonConvert.DeserializeObject<IEnumerable<Row>>(input);
var dict = rows.ToDictionary(x => x.Symbol, x => x, StringComparer.OrdinalIgnoreCase);
After preparing your dictionary once, you can get the corresponding row by using the indexer:
var aaplRow = dict["AAPL"];
I have a class that is instantiated at the beginning of each iteration of a loop. Inside the loop, it's attributes need to be populated with the row values of a table returned by a stored procedure. As I have to iterate through each column of every row, in order to know which attribute of the class needs to be assigned a value and when, I have a dictionary that maps the column names to an index. This index refers to a position in a list that stores an attribute of an instance of the class:
while (reader.Read() && reader.HasRows)
{
Subscription subscription = new Subscription();
List<string> subscrData = new List<string>
{
subscription.attr1,
subscription.attr2,
subscription.attr3,
subscription.attr4
}
Dictionary<string, int> columnDict = new Dictionary<string, int>
{
{"attr1": 0},
{"attr2":1},
{"attr3":2},
{"attr4":3}
}
foreach (string colName in columnDict.Keys)
{
if (reader.GetSchemaTable().Columns[colName] == null)
subscrData[columnDict[colName]] = "null";
else
{
subscrData[columnDict[colName]] = reader[colName].ToString();
nullsReturned = false;
}
}
I'm probably coming at this from more of a C++ approach as with that you could store references to the class instance an modify its attributes, but this doesn't work with C# because lists store the values.
How can I restructure this code so that I can modify the actual attributes of the class instance while still being able to check if each column returned from the stored procedure is not null?
You don't need the list for this case. You either want to add a method like setAttribute(string attributeName) to your class (and within it build a switch/case to modify the given attribute); or, use reflection to change an instance field given its name.
I agree with Hasan. But just for your information: to implement your approach you could make use of Lambda expressions to keep track of the references to your properties (= the attributes).
Something like this would work:
Subscription subscription = new Subscription();
List<Expression<Func<Subscription, string>>> subscrData = new List<Expression<Func<Subscription, string>>>
{
a => a.attr1,
a => a.attr2,
a => a.attr3,
a => a.attr4,
};
//E.g. To update attribute 3 you can do this:
var prop = (PropertyInfo)((MemberExpression)subscrData[2].Body).Member;
prop.SetValue(subscription, "test string", null);
Something like this:
Dictionary<int, string> myData = new Dictionary<int, string>();
myData.Add(1, "England");
myData.Add(2, "Canada");
myData.Add(3, "Australia");
myTreeView.Node[0].Tag = myData;
Then I want to get this object, how should I do it ?
Like:
string str = new string();
str = myTreeView.Node[0].Tag[2]; // "str" should be equal to "Canada"
myTreeView.Node[0].Tag[1] = "Spain";
str = myTreeView.Node[0].Tag[1]; // now "str" is equal to "Spain"
Second question - what will return this expression:
Dictionary<int, string> myData = new Dictionary<int, string>();
myData.Add(1, "England");
myData.Add(2, "Canada");
myData.Add(3, "Australia");
string str1 = new string();
str = myData[4]; // there isn't such a key as 4
Exception or null ?
Control.Tag is typed as object so you'll need to cast it to access it as a Dictionary<int, string>:
Dictionary<int, string> dict = (Dictionary<int, string>)myTreeView.Node[0].Tag;
string str = dict[2];
And similarly to set a value:
var dict = (Dictionary<int, string>)myTreeView.Node[0].Tag;
dict[1] = "Spain";
If you try to access a non-existent key, a KeyNotFoundException will be thrown. You can check if the dictionary contains a given key using TryGetValue or ContainsKey:
if(dict.ContainsKey(key))
{
var value = dict[key];
}
else
{
}
TryGetValue does the lookup and sets the given variable to the value (it it exists) in a single call, so is usually preferred.
string value;
if(dict.TryGetValue(key, out value))
{
//use value
}
else { ... }
Exception or null ?
Well, you could just try it out yourself or read the documentation (it throws an exception).
Also, your code will not compile as posted. Tag is a way to associate arbitrary data with an object. As a result, its type is object, so you will need to cast it before using it as you do.
If your code ever becomes unwieldy due to overuse of the Tag property I would suggest creating your own node type which inherits from the default TreeNode (or whatever it is) and populating your tree view with that type of object instead.
The tightest means for addressing the properties of a node tag is:
((TagType)node_identity.Tag).TagProperty = value;
Thus the tag properties of the parent node can be addressed so:
((TagType)node_identity.Parent.Tag).TagProperty = value;
The tag properties of a child node can be addressed so:
((TagType)node_identity.Nodes[index_of_child].Tag).TagProperty = value;
And as each Nodes[index_identifier] resolves to a node, the tag properties of more remote child nodes can be addressed so:
((TagType)node_identity.Nodes[index_of_child].Nodes[index_of_further_child].Tag).TagProperty = value;
Etc.
As far as the assumable objects of Tagging your dictionary are concerned... assuming your purposes require the same integer-string associations everywhere, I would instead simply store the integer key value to your Tag field, and pull the associated string from perhaps a global List<string> DictionaryStrings object. Then you could store only the integer index value to your Tags; and only the string values to your List<string>.
You would then read your Tag values as follows:
((int)node_identity.Tag)
Given these assumptions, you would instead populate your infrastructure so:
List<string> DictionaryStrings = new List<string>;
DictionaryStrings.Add("Canada"); // etc.
Then you would read the tag to pull your DictionaryString from the index value stored to your Tags as follows:
string DictionaryString = DictionaryStrings[((int)node_identity.Tag)];
Your error message is a consequence of addressing a prospective member of your dictionary which you have not yet added (at that execution point) to your dictionary. Fully populate the List or dictionary first; then only address valid indexes belonging to the List/dictionary.
I'm some what new to linq could uses some help..
I have an xml file that looks like this:
<InputPath>
<path isRename="Off" isRouter="Off" pattern="pattern-1">d:\temp1</path>
<path isRename="Off" isRouter="pattern-1">d:\temp2</path>
</InputPath>
I need to loop through and get the key values of the tag "path".
What I have so far is
var results = from c in rootElement.Descendants("InputPath") select c;
foreach (XElement _path in results)
{
string value = _path.Element("path").Value;
}
But I only get the last <path> value. Any help would be great.
Have you tried just just enumerating the path items?
foreach (var element in rootElement.Descendants("path"))
{
var value = element.Value;
}
You'll only get the first element that way, because that's what the Element method gives you: the first child element with the given name.
If you want multiple elements you can just use Elements instead:
// Note: the query expression here is pointless.
var results = from c in rootElement.Descendants("InputPath") select c;
foreach (XElement _path in results)
{
string value = _path.Elements("path").Value;
// Use value here...
}
Alternatively, use the Elements extension method and do it all in one go:
foreach (var path in rootElement.Descendants("InputPath").Elements("path"))
{
string value = path.Value;
// Use value here
}
If that doesn't help, please give more information about what you're trying to do and what the problem is.
If by "last" you mean "the element contents" that's because you're using the Value property. If you want the attributes within the path element, you need the Attribute method, as shown by IamStalker, although personally I'd usually cast the XAttribute to string (or whatever) rather than using the Value property, in case the attribute is missing. (It depends on what you want the behaviour to be in that case.)
What you need is, to loop through the attributes like so
foreach (XElement xElem in rootElement.Descendants("InputPath"))
{
string isRename = xElem.Attribute("isRename").Value;
}