I'm looking into the possibility of storing settings in an XML file. Here's a simplified version of my code. You don't see it here, but this code is located inside a try block so that I can catch any XmlException that comes up.
XmlReader fileReader = XmlReader.Create(Path.GetDirectoryName(Application.ExecutablePath) + "\\settings.xml");
// Start reading
while (fileReader.Read())
{
// Only concern yourself with start tags
if (fileReader.IsStartElement())
{
switch (fileReader.Name)
{
// Calendar start tag detected
case "Calendar":
//
//
// Here's my question: can I access the children
// of this element here?
//
//
break;
}
}
}
// Close the XML reader
fileReader.Close();
Can I access the children of a certain element on the spot in the code where I put the big comment?
There are applications where using XmlReader to read through an XML document is the right answer. Unless you have hundreds of thousands of user settings that you want to read (you don't) and you don't need to update them (you do), XmlReader is the wrong choice.
Since you're talking about wanting to store arrays and structs in your XML, it seems obvious to me that you want to be using .NET's built in serialization mechanisms. (You can even use XML as the serialization format, if accessing the XML is important to you.) See this page for a starting point.
If you design your settings classes properly (which is not hard), you can serialize and deserialize them without having to write code that knows anything about the names and data types of the properties you're serializing. Your code that accesses the settings will be completely decoupled from the implementation details of how they are persisted, which, as Martha Stewart would say, is a Good Thing.
Check this short article for a solution.
And by the way, you should use LINQ to XML if you want to work easy with XML (overview).
You can use any of the following methods on XmlReader:
ReadSubtree()
ReadInnerXml()
ReadOuterXml()
ReadStartElement()
to read the child content. Which one you use depends on exactly what you wish to do with said child content.
App.config and create a custom section.
App.Config and Custom Configuration Sections
Related
I have already deserialized a json-file to c#-objects. This has been done by the following:
JsonSerializer<FooClass>().DeserializeFromString(json)
and it all works well. I now want to change the json to xml and do the exact same, keeping all the classes and setup, that has already been made inside the solution.
The conversion from json to xml is easy, but I cant figure out how to deserialize the xml so that I dont need to change a lot of code.
Is it possible to keep the whole setup, but somehow change few lines of code such as
JsonSerializer<FooClass>().DeserializeFromString(json)
to something alike, but that deserializes the xml instead?
I've found the following solutions in here, but they don't seem to solve the problem:
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
string jsonText = JsonConvert.SerializeXmlNode(doc);
but the SerializeXmlNode isn't possible?
The other solutions I have found in here use arguments and stuff like that, which again will force me to change some of the setup, which I am not interested in, if possible.
Also I am aware, that a direct transformation from json to xml has its cons, but if we look aside from that and focus on the xml part, then it would be nice.
This because we are writing in xml instead of json from now on and therefore the change needed.
One easy route I can see is to leverage the XmlClass Attributes and use XmlSerializer.
I'm currently using XmlSerializer to, surprisingly enough :), handle de/serialization of my data structures - I find it wonderfully simple to use, but at the cost of flexibility. At the moment, I'm using it for a tree-based structure; since XmlSerializer doesn't handle cyclic structures, I've added [XmlIgnore] to my Parent property, and do a post-deserialization iteration over the tree to fix up node parents.
Is there a better way to handle this using XmlSerializer, or would it be better to rewrite the code using XmlReader/XmlWriter? I suppose implementing IXmlSerializable would work, but it seems like a fair amount of work, while still retaining the cons of XmlSerializer.
The current post-deserialization step is OK, but I'm adding a data structure that has to be serialized to a separate XML file: basically a flat list of items that need a Parent property referencing a node from the previous tree structure. This would require yet a post-deserialization step, as well as keeping both a Parent attribute as well as as ParentId (or some trickery) in the new data structure.
So, any smart (and non-fragile) ideas? Or XmlReader/XmlWriter it is?
Solution
DataContractSerializer turned out to be a pretty decent solution, with pretty much the same simplicity as XmlSerializer. I opted not to use the automatic cycle handling but instead defining and OnDeserialized decorated method to handle setting the parent node; that way, the generated XML is standard-conforming.
One thing that confused me for a while was that I got crashes on some properties after deserializing, with the backing members set to null - couldn't figure out how this was possible since the backing members were definitely initialized in all possible constructors. Debugging showed constructors were never called, and after some googling I found this SO post with an explanation.
You could try binary serialization (BinarySerializer or DataContractSerializer), which I think handles cyclic graphs somewhat better, at the cost of not having a human-readable representation of the data. Alternatively, you can try the SoapFormatter as detailed here.
Use DataContractSerializer. Mark your classes with [DataContract(IsReference = true)].
If I am dealing with several standard xml formats what would be the best practice way of encapsulating them in C# 3.5? I'd like to end up with something similar to the System.ServiceModel.Syndication namespace.
A class that encapsulates the ADF 1.0 XML standard would be one example. It has the main XML root node, 6 child elements, 4 of which are required IIRC, several required and optional elements and attributes further down the tree. I'd like the class to create, at a minimum, the XML for all the required pieces all the way up to a full XML representation. (Make sense).
With LINQ 4 XML and extension classes, etc, etc, there has to be some ideas on quickly generating a class structure for use. Yes? No? :)
Am not sure if I gave enough details to get one correct answer but am willing to entertain ideas right now.
TIA
XML serialization seems a good approach. You could even use xsd.exe to generate the classes automatically...
EDIT
Note that the class names generated by the tool are usually not very convenient, so you might want to rename them. You might also want to change arrays of T to List<T>, so that you can easily add items where needed.
Assuming the class for the root element is named ADF, you can load an ADF document as follows :
ADF adf = null;
XmlSerializer xs = new XmlSerializer(typeof(ADF));
using (XmlReader reader = XmlReader.Create(fileName))
{
adf = (ADF)xs.Deserialize(reader);
}
And to save it :
ADF adf = ...; // create or modify your document
...
XmlSerializer xs = new XmlSerializer(typeof(ADF));
using (XmlWriter writer = XmlWriter.Create(fileName))
{
xs.Serialize(writer, adf);
}
Why not just follow the pattern of the SyndicationFeed object in the Syndication namespace? Create a class that takes in a Uri to the xml document or just takes in the document fragment.
Then parse the document based on your standards (this parsing can be done using LinqToXml if you wanted to, though regEx might be faster if you are comfortable with them). Throw exceptions or track errors appropriately when the document doesn't pass the specification rules.
If the document passes the parse step then break the pieces of the document out into public getter properties of your object. Then return the fully hydrated object back to the consumer for use
Seems pretty straight forward to me. Is that what you are after or are you looking for something more than this?
I know, where is XmlSchema class in dot net, but it does not allow to load file into it. Is there a clean solution to load xsd file and travel between elements?
You need to use XmlSchemaSet, e.g.:
XmlSchemaSet schemaSet = new XmlSchemaSet();
schemaSet.Add(targetNamespace, schemaUri);
schemaSet.Compile();
foreach(XmlSchemaElement element in schemaSet.GlobalElements.Values)
{
// do stuff...
}
EDIT: Sorry for not being clearer.
Where the comment says // do stuff..., what you need to do is traverse the inherited types of each element, which are available under XmlSchemaElement.SchemaType, and the inline type of the element, which is available under XmlSchemaElement.ElementSchemaType.
The MSDN does contain all the the information you're after, but it is somewhat maze-like and requires digging around plus a bit of trial-and-error to work it out.
As per my comment, the following class from one of my open-source side-projects may be of use to you here:
http://bitbucket.org/philbooth/schemabrute/src/tip/LibSchemaBrute/Navigator.cs
I suggest checking out this tool: http://www.altova.com/xmlspy.html. You can create a data model from any XSD file. I've used it in many XML projects.
I am currently saving a .net ( c# ) usercontrol to the disk as a XML file by saving each property as an element in the xml document. The file is used for later recreation of the controls at runtime. I am wondering if it is possible or better to save the control as a binary file. There would be many controls so I guess it would have to have a header section describing the location and length of each saved controls. Thoughts?
Brad
BTW this is a windows app
EDIT:
what I currently have inplace is a public member function that uses the propertyDescriptior class to itinerate through all the properties and create an xml document from that.
PropertyDescriptorCollection pdc = TypeDescriptor.GetProperties(this);
for (int i = 0; i <= pdc.Count - 1; i++)
{ pdc[i].Name
pdc[i].PropertyType
pdc[i].Category
}
I will look into creating the class Serializable - thanks
We had to do this for a data-driven application where a user could create persistable views. We did an XML version to start but moved to using BinaryFormatter and the ISerializable interface as this allows us to control exactly what gets persisted and which constructors to use. For the controls we actually persisted the CodeCompileUnit that the designer has created, but that means you have to actually use a designer to lay them out.
Winforms controls don't serialize especially well, and you might have a lot of difficulty getting the base-classes (i.e. not your code) to play ball. Things like Color, for example, regularly provide surprisingly troublesome to serialize.
Xml would be an obvious (if somewhat predictable) choice, but you generally need to nominate sub-classes ahead of time. And of course, the base-classes won't be marked serializable. BinaryFormatter would avoid some of that, but as a field-based serializer, you'd have problems with the "handles" etc in the base-classes, which are meaningless serialized.
I'm not saying it can't be done - but it won't be trivial either. As a starter, you'd want to look at TypeConverter.GetProperties, and use the Converter of each to get the value as an invariant string.
just had a thought: maybe you dont need to serialize the base/sub-classes. maybe you could write another searializer that only serializes the top tier of the class inheritance hierarchy? only serializing your classes (you wrote) and maybe storing meta-data for the base classes you may derive from (so that you can re-map this on de-serialization)?? this could just be pie-in-the-sky too.