XML - Serialize class - Some questions - c#

I have the idea of serializing the properties of a class to a XML-file and then upload this file to a server. This is because I want to download this file again and read out the serialized content.
So a structure like this:
File exists (myfile.xml) -> Serialize data from a class (myclass.cs) to the file -> Upload the file.
Now the content could look something like this:
<?xml version="1.0"?>
-<MyClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SomeProperty>0.1.0.0</SomeProperty>
<SomePropertiesChild>Test</SomePropertiesChild>
</MyClass>
Well, so this is not the problem, I have built a class to serialize the data to the file, so that it looks like above.
The problem now is, that I do not know how to go on. I want that the next time new data will be serialized like that, but it should be attached to that XML-file, not a new one.
So I download this file and then serialize new data as attachment to it, so that it will look the following:
<?xml version="1.0"?>
-<MyClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SomeProperty>0.1.0.0</SomeProperty>
<SomePropertiesChild>Test</SomePropertiesChild>
<!-- This is the part that should be attached -->
<SomeProperty>0.2.0.0</SomeProperty>
<SomePropertiesChild>Test2</SomePropertiesChild>
</MyClass>
And this should be repeated as many times as I want: download file, serialize new data and attach it to this one, then upload it again.
Now, the second point is, that I want to read this out.
For that I use the XML-class, too. For the type param for the type that the data should be serialized to, I set the class that contains the properties.
But now, I have more nodes of the same name in my XML like above. I want to separate this now.
So, not only that one class, but for each node with the same name a new class.
To show you that a bit clearer:
In the XML we have the first pair (SomeProperty, SomePropertiesChild).
This one should be deserialized to myclass.cs now, which contains the right properties for the XML-nodes. Example:
public class MyClass
{
public Version SomeProperty {get; set;}
public string SomeProeprtiesChild {get; set;}
}
And then the first XML-pair should be deserialized to that class.
But I want to do this for each XML-"pair" in my XML-file, but I can't get a right structure in my head.
Should I make a List here or how should I do that?
I really hope I could explain it a bit clearly, it is very difficult to explain.
Also I do not know how to do this with the attaching. Any tips?
If you have questions, ask!

What you are looking for is not simply serialization. You want to serialize the same object more than once right?
A possible solution is to serialize a List<MyClass> and append new instances to the list if the file exists.

In short, there is no built-in way to do what it is you are looking for. However, that doesn't mean it can't be done...
The simplest, and closest built-in, way would be to maintain a List<MyClass> which you update whenever you upload/download etc. and serialize. However, this wouldn't get the exact XML you want, this would produce something along the lines of
<ListOfMyClass>
<MyClass>
<Property>1</Property>
...
</MyClass>
<MyClass>
<Property>2</Property>
...
</MyClass>
</ListOfMyClass>
The more complex approach would be to have MyClass implement IXmlSerializable and override the behaviour of WriteXml/ReadXml to handle your custom XML format.

Related

Does the class of an xml configuration file need to match an actual class used in the application?

For a configuration file in XML that you are using to store application settings, does it's class object need to be one of the classes that is used within the application, or do you create a special configuration class and the translate the values inside you application to the other objects that use those values?
For example
Say I want to keep track of these 3 settings for a product
Name
ID
Color
So My config file looks something simple like
<Product>
<Name>product1</Name>
<ID>2343435</ID>
<Color>Blue</Color>
</Product>
But my Product class that I'm using in the application has many more properties and methods
like
class Product{
string Name;
string Color;
int ID;
bool isObsolete;
SpecialType ProductProperty;
Product(){}
ObsoleteProduct(){
//do stuff
}
OtherMethod(){
//Do stuff
}
}
So then am I supposed to make XML representation from the actual Product class I'm using, or do I use the simpler form that only contains the settings I care about? Because if I use the simpler form, then I'll have two classes, and I'll need to move the values between objects.
The xml serialization and deserialization can be configured a lot using attributes, as described here. For instance, properties can be omitted from serialization, the names of properties can be explicitly specified and the serialization styles for array types can be selected.
Furthermore, the access on array types is done via the ICollection interface, which permits to provide additional logic on insertion of elements, which is discussed in this article.

Asp.net XML to objects

I have a XML file, with a structure like
<items>
<item>
<someDetail>
A value here
</someDetail>
</item>
<item>
<someDetail>
Another value here
</someDetail>
</item>
</items>
With multiple items in it.
I want to deserialize the XML on session start ideally, to turn the XML data to objects based on a class (c# asp.net 4)
I have tried several ways with either no success, or a solution which seems clunky and inelegant.
What would people suggest?
I have tried using the xsd.exe tool, and have tried with the xml reader class, as well as usin XElement class to loop through the xml and then create new someObject(props).
These maybe the best and/or only way, but with it being so easy for database sources using the entities framework, I wondered if there was a similar way to do the same but from a xml source.
The best way to deserialize XML it to create a class that corresponds to the XML structure into which the XML data will deserialize.
The latest serialization technology uses Data Contracts and the DataContractSerializer.
You decorate the class I mentioned above with DataMember and DataItem attributes and user the serializer to deserialize.
I'd use directly the .NET XML serialization - classes declarations:
public class Item {
[XmlElement("someDetail")]
public string SomeDetail;
} // class Item
[XmlRoot("items")]
public class MyData {
[XmlElement("item")]
public List<Item> Items;
public static MyData Deserialize(Stream source)
{
XmlSerializer serializer = new XmlSerializer(typeof(MyData));
return serializer.Deserialize(source) as MyData;
} // Deserialize
} // class MyData
and then to read the XML:
using (FileStream fs = new FileStream(#"c:\temp\items.xml", FileMode.Open, FileAccess.Read)) {
MyData myData = MyData.Deserialize(fs);
}
I've concluded is there is not simple unified mechanism (probably due to the inherent complexities involved with non trivial cases - this question always crops up in the context of simple scenarios like your example xml).
Xml serialization is pretty easy to use. For your example, you would just have to create a class to contain a items and another class for the actual item. You might have to apply some attributes to get everything to work correctly, but the coding will not be much. Then it's as easy as -
var serializer = new XmlSerializer(typeof(ItemsContainer));
var items = serializer.Deserialize(...) as ItemsContainer;
Datasets are sometimes considered "yesterday tech" but I use them when they solve the problem well, and you can leverage the designer. The generated code is not pretty but the bottom line is you can persist to a database via the auto generated adapters and to XML using a method right on the data set. You can read it in this way as well.
XSD.exe isn't that bad once you get used to it. I printed the help to a text file and included it in my solutions for a while. When you use the /c option to create classes, you get clean code that can be used with the XmlSerialzier.
Visual Studio 2010 (maybe other versions too) has an XML menu which appears when you have an Xml file open and from that you can also generate an XSD from sample Xml. So in a couple of steps you could take your example xml and generate the XSD, then run it through XSD.exe and use the generated classes with a couple of lines XmlSerializer code... it feels like a lot of machinations but you get used to it.

XML Object Serialization on Collection At Root Level

Trying to deserialize an XML file from a 3rd party tool into a custom software class. The problem is that the XML is a little goofy as the "root" item is really the declaration of the collection. I have done a lot with XMLArray and other definitions to define serialization, but this does not seem to work. The best I have been able to do is to get the collection read in but none of the objects in the collection are initialized with the variables.
Here is an example of what I am facing:
XML:
<Animals>
<Animal>
<Name>Mr. Cow</Name>
<Type>Cow</Type>
</Animal>
<Animal>
<Name>Belle</Name>
<Type>Cow</Type>
</Animal>
<Animal>
<Name>Porky</Name>
<Type>Pig</Type>
</Animal>
</Animals>
I then have my XMLRoot defined as "Animals" in my "Farm" object. And have a list property for my class of "Animal". If I define that property (list AnimalCollection) the best I can get is a list of 3 uninitiated Animal objects (none of the values set).
Around the office, the best we could figure to do was to add a node to the file as a stream before trying to deserialize it and use it business as usual, but obviously this seems like a horrible hack. Hoping that there is a better way that I am just missing.
I have also thought about manually reading the document as well... but again hoping there is a more elegant way.
XmlSerializer serializer = new XmlSerializer(typeof(Animal[]), new XmlRootAttribute("Animals"));
public class Animal
{
[XmlElement]
public string Name;
[XmlElement]
public string Type;
}

Serialization of objects

I'm trying to do something that I can't really find any help on. I have a class, within this class it represents 2 other classes exposed as properties. I want the properties of the classes to sit under the root of the containing class, instead of having the class names and then values:
Example:
public Origin Origin { get; set; }
public Destination Destination { get; set; }
Both these define nodes that should be tagged in the XML as:
<RootClass>
<ValueFromOrigin />
<ValueFromDestination />
</RootClass>
Current, my serialization brings back:
<RootClass>
<Origin>
<ValueFromOrigin />
</Origin>
<Destination>
<ValueFromDestination />
</Destination />
</RootClass>
I have tried adding [XmlElement("RootClass")] to the properties for both Origin and Destination but get an error, assuming that it's trying to duplicate the node for some reason. Has anyone tried this successfully?
Thanks for the help guys.
Eric
You need custom serialization. Without tag information the default serializer wouldn't know how to deserialize all of your data.
Imagine if both those properties were Strings. Which Element goes with which property?
C# Custom Xml Serialization
I think the simplest way if you have xml sample and dont know how to write class, is to use xsd.exe tool to generate classes.
First extract shema using command
xsd.exe your.xml
Second generate
classes from generated schema using
command xsd.exe your.xsd /classes
Its very helpfull when you have big xml schema and dont want to spend many time to write classes for serialization.

Is it possible to set a default value when deserializing xml in C# (.NET 3.5)?

I've got a little problem that's slightly frustrating. Is it possible to set a default value when deserializing xml in C# (.NET 3.5)? Basically I'm trying to deserialize some xml that is not under my control and one element looks like this:
<assignee-id type="integer">38628</assignee-id>
it can also look like this:
<assignee-id type="integer" nil="true"></assignee-id>
Now, in my class I have the following property that should receive the data:
[XmlElementAttribute("assignee-id")]
public int AssigneeId { get; set; }
This works fine for the first xml element example, but the second fails. I've tried changing the property type to be int? but this doesn't help. I'll need to serialize it back to that same xml format at some point too, but I'm trying to use the built in serialization support without having to resort to rolling my own.
Does anyone have experience with this kind of problem?
It looks like your source XML is using xsi:type and xsi:nil, but not prefixing them with a namespace.
What you could do is process these with XSLT to turn this:
<assignees>
<assignee>
<assignee-id type="integer">123456</assignee-id>
</assignee>
<assignee>
<assignee-id type="integer" nil="true"></assignee-id>
</assignee>
</assignees>
into this:
<assignees xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<assignee>
<assignee-id xsi:type="integer">123456</assignee-id>
</assignee>
<assignee>
<assignee-id xsi:type="integer" xsi:nil="true" />
</assignee>
</assignees>
This would then be handled correctly by the XmlSerializer without needing any custom code. The XSLT for this is rather trivial, and a fun exercise. Start with one of the many "copy" XSLT samples and simply add a template for the "type" and "nil" attributes to ouput a namespaced attribute.
If you prefer you could load your XML document into memory and change the attributes but this is not a good idea as the XSLT engine is tuned for performance and can process quite large files without loading them entirely into memory.
You might want to take a look at the OnDeserializedAttribute,OnSerializingAttribute, OnSerializedAttribute, and OnDeserializingAttribute to add custom logic to the serialization process
XmlSerializer uses xsi:nil - so I expect you'd need to do custom IXmlSerializable serialization for this. Sorry.

Categories

Resources