Extend .NET XmlSerializer? - c#

The question is simple as stated in the title.
I need to somehow extend the existing .NET XMLSerializer.
The reasons are
It already does so many things. I do not want to reinvent the wheel.
I need to deserialize a bunch of tags to a key/value pair. E.g.
<City>
<Suburb1>Test1</Suburb1>
<Suburb2>Test2</Suburb2>
</City>
This needs to be deserialized to
`List<KeyValuePair<string,string>` suburbsList
`suburbsList.Add(new KeyValuePair("Suburb1", "Test1"))
`suburbsList.Add(new KeyValuePair("Suburb2", "Test2"))
The example here is simplified, so having strongly typed properties is not an option.
I tried UnknownNode event from the XmlSerializer class but it does not seem to do what I'm intending. TBH, I have not explored a lot on this though.

Related

XmlSerializer that treats null values as empty elements

I'm writing a small C# application that needs to be able to read/write some config data as XML. I'm doing this by creating some simple model classes with properties that have XmlElement attributes where needed, and running the whole thing through an XmlSerializer.
I would like to have the XmlSerializer behave exactly as it usually does, except I want any null properties on serialized objects to be written as empty elements. (Currently it skips them entirely.) And likewise, when deserializing, I'd like it to interpret empty elements as null, rather than as an empty string.
What's the most straight-forward way to achieve this? The suggestions I've seen for similar situations involve using the IsNullable argument for XmlElement, creating ShouldSerialize methods, etc. This has to be done for every property, creating a lot of unnecessary code. In this case, I want it to be universal for anything I'm (de)serializing. If I need to extend XmlSerializer, that's fine, and I could live with implementing IXmlSerializable on the model classes, but I'm not entirely sure where to start with those two possible approaches.

Best way to compare XML in C#

I'm looking for the best way to compare two XML files for difference using C#. Like say for example if I have two XMLs A and B like this:
XML A
<data:TR xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:pd="http://www.ascentn.com/bpm/XMLSchema">
<data:processFields />
<data:formFields>
<data:TextBox1>111</data:TextBox1>
<data:TextBox2>222</data:TextBox2>
<data:TextBox3>3333</data:TextBox3>
<data:Repeat1_Repeat>
<data:Repeat1>
<data:TextBox4>444</data:TextBox4>
<data:TextBox5>555</data:TextBox5>
</data:Repeat1>
</data:Repeat1_Repeat>
</data:formFields>
</data:TR>
XML B
<data:TR xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:pd="http://www.ascentn.com/bpm/XMLSchema">
<data:processFields />
<data:formFields>
<data:TextBox1>111</data:TextBox1>
<data:TextBox2>aaa</data:TextBox2>
<data:TextBox3>3333</data:TextBox3>
<data:Repeat1_Repeat>
<data:Repeat1>
<data:TextBox4>bbb</data:TextBox4>
<data:TextBox5>555</data:TextBox5>
</data:Repeat1>
<data:Repeat1>
<data:TextBox4>ccc</data:TextBox4>
<data:TextBox5>ddd</data:TextBox5>
</data:Repeat1>
</data:Repeat1_Repeat>
</data:formFields>
</data:TR>
I'm looking to get only the different between the two XML files, like in this case it would be TextBox2 and TextBox4 and one full node for Repeat1_Repeat.
Is there a easy way to get this? Maybe use some framework? I'm using .NET 4.5.2 so anything recent would work too!
Thanks!
EDIT : Oh and also, I need it to work for n-level of nesting.
I think XMLDiff is the best way. No framework needed. As seen on MSDN:
By using the XMLDiff class, the programmer is able to determine if the
two files are in fact different based on the conditions that are
important to their application. The programmer is able to ignore
changes that are only superficial (for example, different prefixes for
same namespace). XMLPatch then provides the ability to update the
original XML by applying only the changes that matter to the original
XML.
You should check it out:
https://msdn.microsoft.com/en-us/library/aa302294.aspx
You can use Paste Special to generate classes for your XML.
Then you can deserialise your xml to create an instance of your code generated class.
So for two xml files; you can create two objects like xmlObject1 and xmlObject2.
Then you can use CompareObject to identify the difference between two objects.

Xml serialization and different languages (internationalization)

What is a good solution to do XML serialization in different languages (internationalization) so that tags and attributes are serialized to the same object with different language?
I save configuration in xml and want to support german and english for the xml.
I don't really know how a good approach for this issue looks like.
Best solution would be but doesn´t exist:
[XmlRoot("MyEnglishConfig,MeineDeuscheKonfiguration")]
public class Test
{
[XmlElement(ElementName="Setting1,Einstellung1")]
public String value1;
}
so that both xml versions are parsed correct:
<MyEnglishConfig>
<Setting1>English value</Setting1>
<MyEnglishConfig>
<MeineDeuscheKonfiguration>
<Einstellung1>deutscher Wert</Einstellung1>
</MeineDeuscheKonfiguration>
What is a good solution to do XML serialization in different languages (internationalization) so that tags and attributes are serialized to the same object with different language?
Don't! That simply isn't a good thing to do, and virtually no libraries will help you do it. By all means localize and internationalize a maintenance UI; but leave the xml in a single culture. This is just asking for extreme pain. The type of people who are going to be manually editing an xml file probably aren't going to mind if they need to read tags in a different language.
If you needed to do that, XmlAttributeOverrides can be used to make a per-language serializer, but... yeuch.

XML Serializer, Port from MS to Mono, Order

Circumstances made it necessary to run a .NET 3.5 application on Mono. The application does not use special libraries, but relies heavily on the XML Serializer to load a complex model.
Concrete I have the following situation, an XML statement like:
<compare-clause>
<first-element />
<second-element />
</compare-clause>
While first-element and second-element can be several different types, the order is important, as it defines which is the left and which the right operand. This works always fine on MS, but on Mono (with some elements) there is very strange behaviour. Mono ignores assigning the first property, assigns first-element to the second property on the target object, and leaves out the XML second-element completely.
The XML annotation on the class looks like this:
[XmlElement("first-element"), Type=typeof(FirstElementType), Order=1]
[XmlElement("second-element"), Type=typeof(SecondElementType), Order=1]
public ElementBase Left { ... }
[XmlElement("first-element"), Type=typeof(FirstElementType), Order=2]
[XmlElement("second-element"), Type=typeof(SecondElementType), Order=2]
public ElementBase Right { ... }
As I said, it does not work under some circumstances, sometimes swapping the order helps, although all types have the same structure and the annotation on both properties is the same, except for Order=1,2. This has always worked on MS .NET. Maybe it has something to do, if first-element comes before second-element on the annotation, although this should be completely unrelated according to general attribute specification (order does not matter).
Maybe this is still a bug with Mono XML Serialzer or I have misused it and it just works on MS. Nevertheless, I had to use the latest version of the XML Serializer (January 2013) in order to get the application working at all!
I would be grateful for hints on this.
Best Regards
Ok, I have carefully read the MS .NET Framework documentation again. Seems multiple notation of XMLElementAttribute is only considered an official option for collection-based properties. However, it is misleading that no proper error message is generated when creating the serializer then (both on MS and Mono).
I have made a workaround now for deserializing multiple types by adding an object[] property to the object, and setting XMLIgnore on the official properties of the model. That way, I can also distinguish between several types of elements, even if there is only one element expected.
To make things further clear, to those interested: I needed to deserialize a couple of object types, which are always identified through their element name, on different places within the document hierarchy. However, scalar polymorphic properties seem to serialize/deserialize only with the name specified on the property, and not on the type. That means type discrimination is only based on an attribute (xsi:type) and not on element name.
I have already researched for alternative XML serializer libraries. Although there are a few options with significant improvements, neither seems to be completely flexible or completed, especially in terms of class hierarchies.

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