c# deserialize xml with a specified 'encoding' and 'stylesheet' lines - c#

I am creating an XML file using the System.Xml.Serialization module.
I have a class that gets serialized into an XML file. The file looks like this:
<itemList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<itemListed>
<item ID="81288" Synopsys="Reset search point" CompletedTime="7/27/10 4:12 PM" Resolver="owner1" />
<item ID="81285" Synopsys="Added contructor" CompletedTime="6/05/10 9:23 AM" Resolver="owner2" />
</itemListed>
</itemList>
Problem is, I would like it to generate this:
<?xml version="1.0" encoding="iso-8859-1"?>
<?xml-stylesheet type="text/xsl" href="item.xsl"?>
<itemListed>
<item ID="81288" Synopsys="Reset search point" CompletedTime="7/27/10 4:12 PM" Resolver="owner1" />
<item ID="81285" Synopsys="Added contructor" CompletedTime="6/05/10 9:23 AM" Resolver="owner2" />
</itemListed>
Any idea what I need to change to my class?
My code:
public class Item
{
[XmlAttribute("ID")]
public string ID { get; set; }
[XmlAttribute("Synopsys")]
public string Synopsys { get; set; }
[XmlAttribute("CompletedTime")]
public string CompletedTime { get; set; }
[XmlAttribute("Resolver")]
public string Resolver { get; set; }
}
public class ItemList
{
[XmlArray(ElementName = "itemListed")]
[XmlArrayItem(ElementName = "item")]
public List<Item> ItemList { get; set; }
}
I appreciate any help.
Thanks
Tony

I haven't found an easy way to customize the stylesheet or the encoding line but I found a good suggestion here:
link text
The idea is to pretty much write your own serialization class. I took the idea from the article and I created a class that serializes the class (using the C# library) then a filter modifies the header to modify the encoding line and add the stylesheet line.
When I load the xml, I read the file, I pass it through the filter to remove the stylesheet line and I change back the encoding line. Once I have done that, I use the de-serializer provided by C#.
It seems to work.
Tony

One solution might be to implement IXmlSerializable interface on your class. I'm not sure if the XmlWriter will allow you to write a XML tag or not. Proper way to implement IXmlSerializable?

Related

Deserializing an XML into a object: XML element with xsi:nil="true" should have null value (and not empty value) for respective property in object

When de-serializing the below XML into Parent class, ElementTwo and ElementThree are empty strings, which is expected. But ElementOne should have been null but instead this is also empty string.
What does i:nil="true" mean?
XML
<?xml version = \"1.0\" ?>
<Parent
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ElementOne xsi:nil="true"/>
<ElementTwo></ElementTwo>
<ElementThree />
<ElementFour>Value</ElementFour>
</Parent>
C# Class
public class Parent
{
public string ElementOne { get; set; }
public string ElementTwo { get; set; }
public string ElementThree { get; set; }
public string ElementFour { get; set; }
}
When de-serializing the XML into an object, the XML element with xsi:nil="true" is not being converted as null. Instead, it is assigned as empty string. But I've a requirement where it should be converted as null only. Please help me to figure out a solution or point put where I went wrong
I've given the sample used in below fiddle link:
https://dotnetfiddle.net/VfNJYv
Put
[XmlElement(IsNullable=true)]
above the
Public string ElementOne get/set property
.NET fiddle

Include raw XML when deserializing XML

I have the following XML and classes that are being serialized from it:
<Alerts>
<io id="1">
<name>Foo</name>
<status>Active</status>
</io>
<io id="2">
<name>Bar</name>
<status>Inactive</status>
</io>
</Alerts>
[XmlRoot("Alerts")]
[Serializable]
public class Alerts
{
[XmlElement("io")]
public List<Alert> { get; set; }
}
public class Alert
{
[XmlElement("name")]
public string Name { get; set; }
[XmlElement("status")]
public string Status { get; set; }
}
What I require is a property in my Alert class, that upon deserialization contains the XML of its node. For example, after deserializing the provided XML, I end up with a list of 2 Alert objects. I would need the first alert to have a property that contains this as a string:
<io id="1">
<name>Foo</name>
<status>Active</status>
</io>
Any ideas how I can achieve this?
I think the only way to actually accomplish this is to have a string property, and then in your xml replace the xml reserved characters with entity character references so it doesn't get serialized as xml. So your xml would look something like:
<io id="1">
<name>Foo</name>
<status>Active</status>
<innerAlert>
<io id="3"><name>FooBar</name><status>Inactive</status><innerAlert></innerAlert></io>
</innerAlert>
I still keep going back to my comment and thinking that you might be better off adding a property of type Alert or IEnumerable to your Alert class and let the tree deserialize out all the way down, but maybe that's just not an option to you.

XML serialization query

I have the following XML which needs deserializing/serializing:
<instance>
<dog>
<items>
<item>
<label>Spaniel</label>
</item>
</items>
</dog>
<cat>
<items>
<item>
<label>Tabby</label>
</item>
</items>
</cat>
</instance>
I cannot change the XML structure.
I need to map this to the following class:
[Serializable, XmlRoot("instance")]
public class AnimalInstance
{
public string Dog { get; set; }
public string Cat { get; set; }
}
I'm not really sure where to start on this one without manually parsing the XML. I'd like to keep the code as brief as possible. Any ideas? (and no, my project doesn't actually involve cats and dogs).
A simple working example (skipping the cat for brevity) using System.Xml.Serialization:
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
[XmlRoot("instance")]
public class AnimalInstance {
[XmlElement("dog")]
public Dog Dog { get; set; }
}
public class Dog {
[XmlArray("items")]
[XmlArrayItem("item")]
public List<Item> Items = new List<Item>();
}
public class Item {
[XmlElement("label")]
public string Label { get; set; }
}
class Program {
static void Main(params string[] args) {
string xml = #"<instance>
<dog>
<items>
<item>
<label>Spaniel</label>
</item>
</items>
</dog>
</instance>";
XmlSerializer xmlSerializer = new XmlSerializer(typeof(AnimalInstance));
AnimalInstance instance = (AnimalInstance)xmlSerializer.Deserialize(new StringReader(xml));
}
}
why is it such a problem to write custom parsing code? for your simple example it may actually involve less code to use an XDocument:
XDocument xdoc = XDocument.Parse(xml);
AnimalInstance animal = new AnimalInstance()
{
Dog = xdoc.XPathSelectElement("instance/dog/items/item/label").Value,
Cat = xdoc.XPathSelectElement("instance/cat/items/item/label").Value
};
When in doubt with creating your xml serialization classes, i find the easiest way to solve the problem is to:
dump all your dummy data into an XML file
run xsd.exe to create a .xsd schema file
run xsd.exe on your schema file to create a class file
i wrote a quick tutorial on it in a blog post a while ago:
http://www.diaryofaninja.com/blog/2010/05/07/make-your-xml-stronglytyped-because-you-can-and-its-easy
it takes less than a minute and you can then easily tweak things from there. XSD.exe is your friend
well you may do custom serialization via IXmlSerializable Interface to get structure as you want
You may also transform the XML document using an XSL to a structure you like and deserialize the output of this transformation. But for such an easy structure, you should use another solution like the one provided by Paolo Tedesco.

Why does the OnDeserialization not fire for XML Deserialization?

I have a problem which I have been bashing my head against for the better part of three hours. I am almost certain that I've missed something blindingly obvious...
I have a simple XML file:
<?xml version="1.0" encoding="utf-8"?>
<WeightStore xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Records>
<Record actual="150" date="2010-05-01T00:00:00" />
<Record actual="155" date="2010-05-02T00:00:00" />
</Records>
</WeightStore>
I have a simple class structure:
[Serializable]
public class Record
{
[XmlAttribute("actual")] public double weight { get; set; }
[XmlAttribute("date")] public DateTime date { get; set; }
[XmlIgnore] public double trend { get; set; }
}
[Serializable]
[XmlRoot("WeightStore")]
public class SimpleWeightStore
{
[XmlArrayAttribute("Records")]
private List<Record> records = new List<Record>();
public List<Record> Records { get { return records; } }
[OnDeserialized()]
public void OnDeserialized_Method(StreamingContext context)
{
// This code never gets called
Console.WriteLine("OnDeserialized");
}
}
I am using these in both calling code and in the class files:
using System.Xml.Serialization;
using System.Runtime.Serialization;
I have some calling code:
SimpleWeightStore weight_store_reload = new SimpleWeightStore();
TextReader reader = new StringReader(xml);
XmlSerializer deserializer = new XmlSerializer(weight_store.GetType());
weight_store_reload = (SimpleWeightStore)deserializer.Deserialize(reader);
The problem is that I am expecting OnDeserialized_Method to get called, and it isn't.
I suspect it might have something to do with the fact that it's XML deserialization rather than Runtime deserialization, and perhaps I am using the wrong attribute name, but I can't find out what it might be.
Any ideas, folks?
There's no equivalent of OnDeserialized for XML deserialization.
See this post for workarounds: How do you find out when you've been loaded via XML Serialization?
The only way you could do that in a graceful way is to manually implement IXmlSerializable, which is not fun. Simply; XmlSerializer doesn't support serialization callbacks.
Sometimes, though, you can switch to DataContractSerializer, which still offers xml capabilities but which does support serialization callbacks. Unfortunately the xml options are limited - it won't work for you xml structure, since that uses attributes (DataContractSerializer only supports elements).
You might also look at the comments on this answer, which discusses the points from this.

How can I Serialize Properly

If I have a class MovieClass as
[XmlRoot("MovieClass")]
public class Movie
{
[XmlElement("Novie")]
public string Title;
[XmlElement("Rating")]
public int rating;
}
How can I've an attribute "x:uid" in my "Movie" element, so that the output when XmlSerializer XmlSerializer s = new XmlSerializer(typeof(MovieClass)) was used
is like this:
<?xml version="1.0" encoding="utf-16"?>
<MovieClass>
<Movie x:uid="123">Armagedon</Movie>
</MovieClass>
and not like this
<?xml version="1.0" encoding="utf-16"?>
<MovieClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Movie x:uid="123" Title="Armagedon"/>
</MovieClass>
Note: I want the xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" removed, if possible.
I answered this in your original post, but I think this one is worded better so I will post it here as well, if it gets closed as duplicate you can modify your original post to mirror this question.
I don't think this is possible without having Title be a custom type or explicitly implementing serialization methods.
You could do a custom class like so..
class MovieTitle
{
[XmlText]
public string Title { get; set; }
[XmlAttribute(Namespace="http://www.myxmlnamespace.com")]
public string uid { get; set; }
public override ToString() { return Title; }
}
[XmlRoot("MovieClass")]
public class Movie
{
[XmlElement("Movie")]
public MovieTitle Title;
}
which will produce:
<MovieClass xmlns:x="http://www.myxmlnamespace.com">
<Movie x:uid="movie_001">Armagedon</Movie>
</MovieClass>
Although the serializer will compensate for unknown namespaces with a result you probably won't expect.
You can avoid the wierd behavior by declaring your namespaces and providing the object to the serializer..
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("x", "http://www.myxmlnamespace.com");
It's not valid XML if you don't have x declared as a namespace prefix. Quintin's response tells you how to get valid XML.

Categories

Resources