Reputation: 6242
I'm new to linq to Xml.
I have a recursive method which get as parameter XElement root
which should hold the XML data in a way it will represent the correlating subtree root of a given recursion depth.
void recursiveMethod(XElement root);
To be more specific,also look at this XML example:
<start>
<Class>
<Worker>
<Name> Dan </Name>
<Phone> 123 </Phone>
<Class>
<Address>
<Street> yellow brick road </Street>
<Zip Code> 123456 </Zip Code>
</Address>
</Class>
</Worker>
</Class>
...
</start>
As you can imagine, Name
is value type whereas Address
is a class reference.
The Xml information should be added dynamically through reflection ( in top down approach).
To make the long story short imagine that I'm in the middle of investigating Worker
Class and reached Address
Class and want to "drill down", so I want to call my recursive method with the right reference of child nodes of the current Worker class as the new XElement root, so I will be able to add to it what I found by reflection in the Address
Class one recursion depth below.
Note that this reference should be of XElement type.
How can I do that?
EDIT: If you have another idea of doing all this stuff but not with XElement
I'll be happy to hear about also, although I prefer it with XElement
parameter.
Another issue:
I've started implementing it in a naive way like iterating through all fields (variable of FieldInfo[]), and if I had encounterd value type(IsValueType) I was doing something like
root.Add(new XElement("Field",
new XElement("Type", ...),
new XElement("Variable Name", ...),
new XElement("Value", ...)));
So ,just for general knowledge:
1. Was there a way to get only the reference of a node to its decendants ,so that in lower recursion level I'll be able to do another root.Add(...) as above but this root will be a reference to children of previous root? (Which means doing the whole operation without Linq syntax)
2.I've managed to get private fields value through reflection without working with properties, is it problematic? Should I always take values through properties in reflection?
Upvotes: 3
Views: 3169
Reputation: 236318
This extension method will build XElement in required format:
public static class Extensions
{
public static XElement ToXml<T>(this T obj)
{
Type type = typeof(T);
return new XElement("Class",
new XElement(type.Name,
from pi in type.GetProperties()
where !pi.GetIndexParameters().Any()
let value = (dynamic)pi.GetValue(obj, null)
select pi.PropertyType.IsPrimitive ||
pi.PropertyType == typeof(string) ?
new XElement(pi.Name, value) :
Extensions.ToXml(value)
)
);
}
}
What happens here:
dynamic
object. It's important, otherwise property value type will be inferred as object
during recursive call of ToXml<T>
method.Usage:
Worker worker = new Worker()
{
Name = "Serge",
Phone = "911",
Address = new Address() { Street = "Elm street", ZipCode = 666 }
};
XElement xml = worker.ToXml();
Result:
<Class>
<Worker>
<Name>Serge</Name>
<Phone>911</Phone>
<Class>
<Address>
<Street>Elm street</Street>
<ZipCode>666</ZipCode>
</Address>
</Class>
</Worker>
</Class>
BUT you should be careful with situations when two objects refer each other (infinite recursion will happen in this case)
In this case you can use something like dictionary or hashset to store all objects which already exist in your xml:
Type type = obj.GetType();
if (set.Contains(obj))
return new XElement("Class", new XAttribute("name", type.Name));
set.Add(obj);
return new XElement("Class", ...);
Upvotes: 5