How to convert objects in reflection - c#

I have this piece of code which is working fine,
My question is if i want to add another element to the xml named 'Allow'. the Allow Element can get the values of 'True' or 'False'. I want to convert it to a boolean property in my Plugin class, meaning the Plugin will have the additional property:
public bool Allow { get; set; }
is there a possibility to convert it?
can you give a code example?
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Xml.Linq;
using System.Reflection;
using System.Text;
namespace WindowsFormsApplication1
{
public abstract class Plugin
{
public string Type { get; set; }
public string Message { get; set; }
}
public class FilePlugin : Plugin
{
public string Path { get; set; }
}
public class RegsitryPlugin : Plugin
{
public string Key { get; set; }
public string Name { get; set; }
public string Value { get; set; }
}
static class MyProgram
{
[STAThread]
static void Main(string[] args)
{
string xmlstr =#"
<Client>
<Plugin Type=""FilePlugin"">
<Message>i am a file plugin</Message>
<Path>c:\</Path>
</Plugin>
<Plugin Type=""RegsitryPlugin"">
<Message>i am a registry plugin</Message>
<Key>HKLM\Software\Microsoft</Key>
<Name>Version</Name>
<Value>3.5</Value>
</Plugin>
</Client>
";
Assembly asm = Assembly.GetExecutingAssembly();
XDocument xDoc = XDocument.Load(new StringReader(xmlstr));
Plugin[] plugins = xDoc.Descendants("Plugin")
.Select(plugin =>
{
string typeName = plugin.Attribute("Type").Value;
var type = asm.GetTypes().Where(t => t.Name == typeName).First();
Plugin p = Activator.CreateInstance(type) as Plugin;
p.Type = typeName;
foreach (var prop in plugin.Descendants())
{
type.GetProperty(prop.Name.LocalName).SetValue(p, prop.Value, null);
}
return p;
}).ToArray();
//
//"plugins" ready to use
//
}
}
}

change
foreach (var prop in plugin.Descendants())
{
type.GetProperty(prop.Name.LocalName).SetValue(p, prop.Value, null);
}
to
foreach (var prop in plugin.Descendants())
{
var pi = type.GetProperty(prop.Name.LocalName);
object newVal = Convert.ChangeType(prop.Value, pi.PropertyType);
pi.SetValue(p, newVal, null);
}
PS:
use <Allow>true</Allow> not <Allow>True</Allow>

Related

How to parse this xml tree

I want to parse tree but it seems many nodes have the same name and attribute as well, so trying to parse it in a efficient way so it can be reused via classes.
<TestStructure>
<TestStructureElement Id="ID_TSE_6" Type="FunctionHierarchy" ObjectRef="ID_FuncHierarchy_7" T42ElementId="31391123">
<TestStructureElement Id="ID_TSE_12" Type="Function" ObjectRef="ID_Function_13" T42ElementId="31391126">
<TestStructureElement Id="ID_TSE_14" Type="Function" ObjectRef="ID_Function_15" T42ElementId="31391127">
<TestStructureElement Id="ID_TSE_16" Type="Function" ObjectRef="ID_Function_17" T42ElementId="31391128"/>
</TestStructureElement>
<TestStructureElement Id="ID_TSE_18" Type="Function" ObjectRef="ID_Function_19" T42ElementId="31391129">
<TestStructureElement Id="ID_TSE_20" Type="Function" ObjectRef="ID_Function_21" T42ElementId="31391130"/>
</TestStructureElement>
<TestStructureElement Id="ID_TSE_26" Type="TestCase" ObjectRef="ID_TestCase_27" T42ElementId="31391133" DOORSId="ESP-TC-104">
<TestResults TestState="EXECUTED">
<Evaluations>
<Evaluation VDSEvaluation="VDS_8">
<Remark>Hochreibwert =1 nicht gegeben</Remark>
</Evaluation>
</Evaluations>
<TestCaseActivities>
<TestCaseActivity TCActivity="TESTCASE" TCActivityState="NONE"/>
<TestCaseActivity TCActivity="VDS" TCActivityState="NONE"/>
<TestCaseActivity TCActivity="SETUP" TCActivityState="NONE"/>
<TestCaseActivity TCActivity="RESUBMISSION" TCActivityState="NONE"/>
</TestCaseActivities>
</TestResults>
</TestStructureElement>
</TestStructure>
Try xml linq. I usd a recursive algorithm
Code below assumes only one Test Report and makes it static
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
new TestStructureElement(FILENAME);
}
}
public class TestStructureElement
{
public static TestStructureElement root = new TestStructureElement();
public string id { get; set; }
public string _Type { get; set;}
public string objectRef { get; set; }
public int t42ElementId { get;set;}
public List<TestStructureElement> children { get;set;}
public static TestResults testResults { get; set; }
public TestStructureElement() { }
public TestStructureElement(string filename)
{
XDocument doc = XDocument.Load(filename);
XElement testStructure = doc.Descendants("TestStructureElement").FirstOrDefault();
GetTree(testStructure, root);
}
public void GetTree(XElement xml, TestStructureElement testStructure)
{
testStructure.id = (string)xml.Attribute("Id");
testStructure._Type = (string)xml.Attribute("Type");
testStructure.objectRef = (string)xml.Attribute("ObjectRef");
testStructure.t42ElementId = (int)xml.Attribute("T42ElementId");
if (xml.Elements("TestStructureElement") != null)
{
testStructure.children = new List<TestStructureElement>();
foreach (XElement child in xml.Elements("TestStructureElement"))
{
TestStructureElement childStructure = new TestStructureElement();
testStructure.children.Add(childStructure);
GetTree(child, childStructure);
}
}
TestStructureElement.testResults = xml.Descendants("TestResults").Select(x => new TestResults()
{
testState = (string)x.Attribute("TestState"),
evalaution = (string)x.Descendants("Evaluation").FirstOrDefault().Attribute("VDSEvaluation"),
evaluationRemark = (string)x.Descendants("Evaluation").FirstOrDefault().Element("Remark"),
testCaseActivity = x.Descendants("TestCaseActivity")
.GroupBy(y => (string)y.Attribute("TCActivity"), z => (string)z.Attribute("TCActivityState"))
.ToDictionary(y => y.Key, z => z.FirstOrDefault())
}).FirstOrDefault();
}
}
public class TestResults
{
public string testState { get; set; }
public string evalaution { get; set; }
public string evaluationRemark { get; set; }
public Dictionary<string, string> testCaseActivity { get; set; }
}
}
Code below has one change which doesn't make Test Report Static
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
new TestStructureElement(FILENAME);
}
}
public class TestStructureElement
{
public static TestStructureElement root = new TestStructureElement();
public string id { get; set; }
public string _Type { get; set;}
public string objectRef { get; set; }
public int t42ElementId { get;set;}
public List<TestStructureElement> children { get;set;}
public TestResults testResults { get; set; }
public TestStructureElement() { }
public TestStructureElement(string filename)
{
XDocument doc = XDocument.Load(filename);
XElement testStructure = doc.Descendants("TestStructureElement").FirstOrDefault();
GetTree(testStructure, root);
}
public void GetTree(XElement xml, TestStructureElement testStructure)
{
testStructure.id = (string)xml.Attribute("Id");
testStructure._Type = (string)xml.Attribute("Type");
testStructure.objectRef = (string)xml.Attribute("ObjectRef");
testStructure.t42ElementId = (int)xml.Attribute("T42ElementId");
if (xml.Elements("TestStructureElement") != null)
{
testStructure.children = new List<TestStructureElement>();
foreach (XElement child in xml.Elements("TestStructureElement"))
{
TestStructureElement childStructure = new TestStructureElement();
testStructure.children.Add(childStructure);
GetTree(child, childStructure);
}
}
testStructure.testResults = xml.Descendants("TestResults").Select(x => new TestResults()
{
testState = (string)x.Attribute("TestState"),
evalaution = (string)x.Descendants("Evaluation").FirstOrDefault().Attribute("VDSEvaluation"),
evaluationRemark = (string)x.Descendants("Evaluation").FirstOrDefault().Element("Remark"),
testCaseActivity = x.Descendants("TestCaseActivity")
.GroupBy(y => (string)y.Attribute("TCActivity"), z => (string)z.Attribute("TCActivityState"))
.ToDictionary(y => y.Key, z => z.FirstOrDefault())
}).FirstOrDefault();
}
}
public class TestResults
{
public string testState { get; set; }
public string evalaution { get; set; }
public string evaluationRemark { get; set; }
public Dictionary<string, string> testCaseActivity { get; set; }
}
}

Parameterless constructor when using XmlSerializer [duplicate]

This question already has answers here:
Why XML-Serializable class need a parameterless constructor
(5 answers)
Closed 6 years ago.
I'm currently trying to copy (by use of code) a .xml file and have approached it many different ways. This way however seems to be the one I get the most as i have I've it before but to create a console.writeline output. I can't seem to get it to work for a console.out when producing the .xml layout. It gives me the following error
"cannot be serialized because it does not have a parameterless constructor"
please could anyone help me with this.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"SmallResults.xml";
static void Main(string[] args)
{
List<BasicEvent> NewBasicEvent = new List<BasicEvent>();
XmlTextReader fileReader = new XmlTextReader("SmallResults.xml");
XmlDocument xml = new XmlDocument();
xml.Load(fileReader);
XmlNodeList BasicEvents = xml.SelectNodes("/HiP-HOPS_Results/FaultTrees/FMEA/Component/Events/BasicEvent");
if (BasicEvents != null)
{
XmlNode[] nodearray = BasicEvents.Cast<XmlNode>().ToArray();
for (int i = 0; i < BasicEvents.Count; i++)
{
NewBasicEvent.Add(new BasicEvent(nodearray[i].FirstChild.NextSibling.InnerText, nodearray[i].FirstChild.NextSibling.NextSibling.InnerText, nodearray[i].FirstChild.NextSibling.NextSibling.InnerText, nodearray[i].FirstChild.NextSibling.NextSibling.NextSibling.InnerText));
new XmlSerializer(typeof(BasicEvent)).Serialize(Console.Out, nodearray );
}
}
}
}
public class FMEA
{
public List<Component> components { get; set; }
}
public class Component
{
public string CompName { get; set; }
public string BasicEventID { get; set; }
public List<BasicEvent> basicevents { get; set; }
}
public class Events
{
}
public class BasicEvent
{
public string BasicEventName { get; set; }
public string BasicEventShortName { get; set; }
public string BasicEventDescription { get; set; }
public string BasicEventUnavalability { get; set; }
public List<Effects> effects { get; set; }
public BasicEvent( string basiceventname, string basiceventshortname, string basiceventdescription, string basiceventunavalability )
{
BasicEventName = basiceventname;
BasicEventShortName = basiceventshortname;
BasicEventDescription = basiceventdescription;
BasicEventUnavalability = basiceventdescription;
}
The message in the exception is quite clear!
Add the default constructor then:
public BasicEvent( ){}

Serialize List<Object> that property of list item is element name in XML

I don't know if the topic is correct, if not please correct. So far i am not sure what to search for my problem so maybe the question has already been answered before.
Currently i have the following class (as example):
[Serializable]
public class Sample
{
public string Something { get; set; }
public List<Parameter> Parameters { get; set; }
}
[Serializable]
public class Parameter
{
public string Name { get; set; }
public string Value { get; set; }
}
This structure i have to serialize to the following XML:
<Sample>
<Something>1234512345112345</Something>
<Parameters>
<Name>Value</Name>
<Name>Value</Name>
</Parameters>
</Sample>
So the XML should contain the property value of the attribute "Name" as XML-Element Name.
Update 20.05.2015
I have the following XML content:
<?xml version="1.0" encoding="utf-16" ?>
<ProcessData>
<ID>123456</ID>
<IDYTPE>BASEPLATE</IDYTPE>
<State>FAIL</State>
<Recipe>654321</Recipe>
<ProcessDataParameter>
<test_0>0</test_0>
<test_1>12,34</test_1>
<test_2>24,68</test_2>
<test_3>37,02</test_3>
<test_4>49,36</test_4>
<test_5>61,7</test_5>
</ProcessDataParameter>
</ProcessData>
When i try to use the following code to deserialize:
public void ReadXml(XmlReader reader)
{
reader.ReadStartElement("ProcessData");
this.Id = reader.ReadElementString("ID");
this.IdType = reader.ReadElementString("IDYTPE");
this.State = reader.ReadElementString("State");
this.Recipe = reader.ReadElementString("Recipe");
reader.ReadStartElement("ProcessDataParameter");
this.ProcessDataParameter = new List<ProcessDataParameter>();
var subTree = reader.ReadSubtree();
while (subTree.Read())
{
if (subTree.NodeType == XmlNodeType.Text)
{
var nm = subTree.LocalName;
//Parameters.Add(new Parameter { Name = nm, Value = subTree.Value });
}
}
reader.ReadEndElement();
}
Everything gets read out fine expect the process data parameters.
It seems like the subTree.Read() just reades the element out of the XML content instead of all elements contained in the .
In the while loop the reader goes through the following values (debuged)
test_0 (start tag)
0 (value between the tag)
test_0 (end tag
and then out of the while.
Seems like the reader sees the as an subtree.
Further only the 0 - value gets recognized as XmlNodeType.Text
You could implement IXmlSerializable and create your own custom serialization behaviour for your Sample class. So in your case something like this should work
[Serializable]
public class Sample : IXmlSerializable
{
public string Something { get; set; }
public List<Parameter> Parameters { get; set; }
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
XmlDocument doc = new XmlDocument();
doc.Load(reader);
Something = doc.SelectSingleNode(#"/Sample/Something").FirstChild.Value;
var parameters = doc.SelectSingleNode(#"/Sample/Parameters");
if (parameters.HasChildNodes)
{
Parameters = new List<Parameter>();
foreach (XmlElement childNode in parameters.ChildNodes)
{
Parameters.Add(new Parameter {Name = childNode.LocalName, Value = childNode.FirstChild.Value});
}
}
}
public void WriteXml(XmlWriter writer)
{
writer.WriteElementString("Something", this.Something);
writer.WriteStartElement("Parameters");
foreach (var parameter in Parameters)
{
writer.WriteElementString(parameter.Name, parameter.Value);
}
writer.WriteEndElement();
}
}
Updated to include ReadXml implementation for deserialization
I'm not quite sure if the ReadXml is complete as I can't test this now, you might have to tweak it a bit for the Parameters
Try this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
Sample sample = new Sample(){
Something = "1234512345112345",
Parameters = new List<Parameter>(){
new Parameter(){
Name = new List<string>(){"Value", "Value"}
}
}
};
XmlSerializer serializer = new XmlSerializer(typeof(Sample));
StreamWriter writer = new StreamWriter(FILENAME);
serializer.Serialize(writer, sample);
writer.Flush();
writer.Close();
writer.Dispose();
XmlSerializer xs = new XmlSerializer(typeof(Sample));
XmlTextReader reader = new XmlTextReader(FILENAME);
Sample newSample = (Sample)xs.Deserialize(reader);
}
}
[XmlRoot("Sample")]
public class Sample
{
[XmlElement("Something")]
public string Something { get; set; }
[XmlElement("Parameters")]
public List<Parameter> Parameters { get; set; }
}
[XmlRoot("Parameters")]
public class Parameter
{
[XmlElement("Name")]
public List<string> Name { get; set; }
}
}
​

How to deep search through every field in a complex object?

I'm using C#, ASP.NET, I use UPS API Tracking to get the Delivery Info, upon making the request, I got back an object (trackResponse) which is very complex and has a lot of field/property or other object embedded inside it.
How do I program to search for every possible value field (string/int/double) in that object?
Basically I want a method like this:
public static bool FindValueInObject(object Input, object SearchValue)
{
Type MyType = Input.GetType();
var props = typeof(MyType).GetProperties();
foreach (PropertyInfo propertyInfo in props)
{
//Console.WriteLine(string.Format("Name: {0} PropertyValue: {1}", propertyInfo.Name, propertyInfo.GetValue(mco, null)));
Type ObjectType = propertyInfo.GetType();
Type SearchType = SearchValue.GetType();
object ObjectValue = propertyInfo.GetValue(Input, null);
if (ObjectType == SearchType)
{
if(ObjectValue == SearchValue)
{
return true;
}
}
else
{
FindValueInObject(ObjectValue, SearchValue);
}
}
return false;
}
But the code above didn't work. Please take a look.
Here ya go....
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
var mco = new MyComplexObject();
mco.MyDate1 = DateTime.Now;
mco.MyDate2 = DateTime.Now;
mco.MyDate3 = DateTime.Now;
mco.MyString1 = "String1";
mco.MyString2 = "String1";
mco.MyString3 = "String1";
var props = typeof(MyComplexObject).GetProperties();
foreach (PropertyInfo propertyInfo in props)
{
Console.WriteLine(string.Format("Name: {0} PropertyValue: {1}", propertyInfo.Name, propertyInfo.GetValue(mco, null)));
}
Console.ReadLine();
}
}
public class MyComplexObject
{
public string MyString1 { get; set; }
public string MyString2 { get; set; }
public string MyString3 { get; set; }
public DateTime MyDate1 { get; set; }
public DateTime MyDate2 { get; set; }
public DateTime MyDate3 { get; set; }
}
}

C# deserialization element mapping

I would like to deserialize the following XML into the following type. How do I map the status correctly? (it is currently not mapped and remains null after the deserialization process)
<?xml version="1.0" encoding="UTF-8"?>
<job:job-status xsi:schemaLocation="http://marklogic.com/xdmp/job-status job-status.xsd" xmlns:job="http://marklogic.com/xdmp/job-status" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<job:forest>
<job:forest-name>FOREST2</job:forest-name>
<job:forest-id>1168048654236455340</job:forest-id>
<job:status>completed</job:status>
<job:journal-archiving>false</job:journal-archiving>
</job:forest>
</job:job-status>
[XmlRoot("job-status", Namespace = "http://marklogic.com/xdmp/job-status")]
public class DatabaseRestoreStatus
{
[XmlElement("status")]
public string Status { get; set; }
}
Using DataContract Serializer worked for me. I also had to create one more class.
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
namespace SandboxConoleApp
{
internal class Program
{
private static void Main(string[] args)
{
DatabaseRestoreStatus data = null;
using (var stream = File.Open("test.xml",FileMode.Open))
{
var formatter = new DataContractSerializer(typeof(DatabaseRestoreStatus));
data = (DatabaseRestoreStatus)formatter.ReadObject(stream);
}
}
}
[DataContract(Name = "job-status", Namespace = "http://marklogic.com/xdmp/job-status")]
public class DatabaseRestoreStatus
{
[DataMember(Name = "forest")]
public Forest Forest { get; set; }
}
[DataContract(Name = "forest", Namespace = "http://marklogic.com/xdmp/job-status")]
public class Forest
{
[DataMember(Name = "status")]
public string Status { get; set; }
}
}

Categories