Deserialize xml node's attributes to class - c#

I have two classes that look like this:
[XmlRoot("Foo")]
public class Foo
{
[XmlArray("BarResponse")]
[XmlArrayItem("Bar")]
public List<Bar> bar {get; set;}
//some other elements go here.
}
[XmlRoot("Bar")]
public class Bar
{
[XmlAttribute("id")]
public Int32 Id {get; set;}
//some other elements go here.
}
The xml I'm receiving looks like this:
<?xml version="1.0"?>
<Foo>
<BarResponse>
<Bar id="0" />
<Bar id="1" />
</BarResponse>
</Foo>
When I attempt to deseralize this, I get an instance of the "Foo" class, and bar has one element in it, with all of it's properties null or default. Where am I going wrong?

try this:
[TestFixture]
public class BilldrTest
{
[Test]
public void SerializeDeserializeTest()
{
var foo = new Foo();
foo.Bars.Add(new Bar { Id = 1 });
foo.Bars.Add(new Bar { Id = 2 });
var xmlSerializer = new XmlSerializer(typeof (Foo));
var stringBuilder = new StringBuilder();
using (var stringWriter = new StringWriter(stringBuilder))
{
xmlSerializer.Serialize(stringWriter, foo);
}
string s = stringBuilder.ToString();
Foo deserialized;
using (var stringReader = new StringReader(s))
{
deserialized = (Foo) xmlSerializer.Deserialize(stringReader);
}
Assert.AreEqual(2,deserialized.Bars.Count);
}
}
[XmlRoot("Foo")]
public class Foo
{
public Foo()
{
Bars= new List<Bar>();
}
[XmlArray("BarResponses")]
[XmlArrayItem(typeof(Bar))]
public List<Bar> Bars { get; set; }
//some other elements go here.
}
[XmlRoot("Bar")]
public class Bar
{
[XmlAttribute("id")]
public Int32 Id { get; set; }
//some other elements go here.
}
You can find info on the use of XmlRoot here
ArrayItemAttribute is used if you expect the array to contain different types
You would get the same result stripping all attributes except for [XmlAttribute("id")], but I guess this is an excerpt from a context where it all is justified.

You need to add a default constructor for the Foo class that instantiates your List<Bar>.
[Serializable]
public class Foo
{
public Foo()
{
Bar = new List<Bar>();
}
[XmlArray("BarResponse")]
[XmlArrayItem("Bar")]
public List<Bar> Bar { get; set; }
}
[Serializable]
public class Bar
{
[XmlAttribute("id")]
public Int32 Id { get; set; }
}
Writes/Reads xml as:
<?xml version="1.0" encoding="utf-8"?>
<Foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<BarResponse>
<Bar id="0" />
<Bar id="1" />
</BarResponse>
</Foo>

Related

Serialize Class to flat XML

Essentially, I need to serialize a C# object to an xml document with an entirely different xml structure and different class/node names. The structure of the C# class is:
public class Root
{
public item item {get; set}
}
public class item
{
public string name {get; set}
public color[] color
}
public class color
{
public string itemColor {get; set}
}
Lets say our item is a car. This serializes to
<Root>
<item>
<name>car</name>
<color>
<itemColor>red</itemColor>
<itemColor>blue</itemColor>
<itemColor>gree</itemColor>
</Color>
</item>
</Root>
But I need this to serialize to:
<Root>
<item>
<name>car</name>
<itemColor>red</itemColor>
</item>
<name>car</name>
<itemColor>blue</itemColor>
</item>
<item>
<name>car</name>
<itemColor>green</itemColor>
</item>
</Root>
I'm currently using IXmlSerializable to try and specify a schema. What is the optimal way of doing this? Should I convert to a second custom object?
Try this:
public class Root
{
[XmlIgnore]
public item item { get; set; }
[EditorBrowsable(EditorBrowsableState.Never)]
[XmlAnyElement("item")]
public List<XElement> _item
{
get
{
return item.color.Select(i =>
new XElement("item",
new XElement("name", item.name),
new XElement("itemColor", i.itemColor)
)).ToList();
}
}
}
public class item
{
public string name { get; set; }
public color[] color;
}
public class color
{
public string itemColor { get; set; }
}
Also, it would be better to use nameof instead of hardcoded literals.
[XmlAnyElement(nameof(item))]
public List<XElement> _item
{
get
{
return item.color.Select(i =>
new XElement(nameof(item),
new XElement(nameof(item.name), item.name),
new XElement(nameof(i.itemColor), i.itemColor)
)).ToList();
}
}

Serializing list of nullable CDATA

I am trying to deserialize a XML file:
<?xml version="1.0" encoding="UTF-8"?>
<Foos xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<FooList>
<Foo>
<Bar>bar value</Bar>
<Stack />
</Foo>
<Foo>
<Bar>bar value</Bar>
<Stack><![CDATA[This is some cdata, where <br> html code is left as is..]]></Stack>
</Foo>
</FooList>
</Foos>
Into the following class
[XmlRoot("Foos")]
public class Foos
{
[XmlArray("FooList")]
[XmlArrayItem("Foo")]
public List<Foo> FooList { get; set; }
}
public class Foo
{
public string Bar { get; set; }
[XmlElement("Stack", typeof(XmlCDataSection))]
public XmlCDataSection Stack {get; set; }
}
The problem is, that the resulting FooList of Foos only contains one (1) element, which is the first Foo block, with the Slack property set to null. If i add a CDATA value to stack, like with the second Foo block, then i will end up with a list of both elements.
For some reason, the deserialization stops, after reaching a CDATA value which is null.
I have tried creating a private string and creating the setter and getter of Stack, such that is uses the private property to store the CDATA string. This doesn't change anything.
Any suggestions?
Thank you.
Get to a cdata section through a string. Object model:
[Serializable]
[XmlRoot("Foos", Namespace="", IsNullable=false)]
public partial class Foos {
[XmlArrayItem ("Foo", IsNullable=false)] public Foo[] FooList { get; set; } }
[Serializable] public partial class Foo {
public string Bar { get; set; }
[XmlIgnore] public string Stack { get; set; }
[XmlElement("Stack", IsNullable=true)]
public XmlCDataSection StackCDATA {
get { return new XmlDocument().CreateCDataSection(Stack ?? String.Empty); }
set {
Stack = value == null
? String.Empty
: ( String.IsNullOrWhiteSpace(value.Value)
? String.Empty
: value.Value); } }
public override string ToString() { return String.Format("Bar:{0} Stack:{1}", Bar, Stack); } }
The right way to specify a null element is <Stack xsi:nil='true' />. With this addition, your deserialization will be flawless. However, on the first occurrence of <Stack />, the deserializer will encounter an unknown node. Workaround in case you are missing this attribute, subscribe to UnknownElement:
var fooSrlz = new XmlSerializer(typeof(Foo), new XmlRootAttribute { ElementName = "Foo", IsNullable = true} );
var foosMissedByDeserializer = new List<CData.Foo>();
srlz.UnknownElement += (/*object*/ sender, /*XmlElementEventArgs */ e) => {
using (TextReader tr = new StringReader(e.Element.OuterXml)) {
var foo = (CData.Foo)fooSrlz.Deserialize(tr);
foosMissedByDeserializer.Add (foo);
} };
Merge the deserialization result with the foosMissedByDeserializer above.

Deserializing an XML document with the root being a list

I have an XML document provided to me externally that I need to import into my application. The document is badly written, but not something I can really do much about.
<?xml version="1.0" encoding="iso-8859-1"?>
<xml>
<Items>
<Property1 />
<Property2 />
...
</Items>
<Items>
<Property1 />
<Property2 />
...
</Items>
...
</xml>
How should I go about using the XmlSerializer for this?
It doesn't seem to matter what class setup I use, or wether I put XmlRoot(ElementName="xml") on my base class it always says that the <xml xmlns=''> is unexpected.
Edit: Added the C# code I am using
[XmlRoot(ElementName = "xml")]
public class Container
{
public List<Items> Items { get; set; }
}
public class Items
{
public short S1 { get; set; }
public short S2 { get; set; }
public short S3 { get; set; }
public short S4 { get; set; }
public short S5 { get; set; }
public short S6 { get; set; }
public short S7 { get; set; }
}
public class XMLImport
{
public Container Data{ get; private set; }
public static XMLImport DeSerializeFromFile(string fileName)
{
XMLImport import = new XMLImport();
XmlSerializer serializer = new XmlSerializer(typeof(Container));
using (StreamReader reader = new StreamReader(fileName))
import.Data = (Container)serializer.Deserialize(reader);
return import;
}
}
Say you have a class Items maps to each <Items> node:
public class Items
{
public string Property1 { get; set; }
public string Property2 { get; set; }
}
You can deserialize your list of Items like this:
var doc = XDocument.Parse(
#"<?xml version=""1.0"" encoding=""iso-8859-1""?>
<xml>
<Items>
<Property1 />
<Property2 />
</Items>
<Items>
<Property1 />
<Property2 />
</Items>
</xml>");
var serializer = new XmlSerializer(typeof(List<Items>), new XmlRootAttribute("xml"));
List<Items> list = (List<Items>)serializer.Deserialize(doc.CreateReader());
The root of your XML is not a List, the root of your xml is the <xml> node I think you are just confused by its name :)
please visit the following link, It has many good answers voted by many people.
Here is the link: How to Deserialize XML document
Error Deserializing Xml to Object - xmlns='' was not expected
Simply take off the Namespace =:
[XmlRoot("xml"), XmlType("xml")]
public class RegisterAccountResponse {...}

DataContract deserializer with Dictionary

If i have an xml like:
<Foo>
<Bar>
<A>aaaa</A>
<B>bbb</B>
</Bar>
<C>ccc</C></Foo>
Can I deserialize it into a Foo class with a dictionary structure and a string property like following using the same DataContract Deserializer? With A and B as the keys and the "aaaa" and "bbb" as the Values in the dictionary?
[DataContract]
class Foo
{
[DataMember]
public Dictionary<string, string> Bar
{ get; set; }
[DataMember]
public string C { get; set; }
}
I know there is an example using CollectionDataContract on MSDN site but it only uses the A as the key and B as the value.
There's no way to do this automatically. If you want a dictionary, you should use LINQ to XML, and create one yourself.
I think the closest thing you'll be able to get to is something like this
<UserQuery.Foo xmlns="http://schemas.datacontract.org/2004/07/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Bar>
<Barentry>
<A>aaa</A>
<B>bbb</B>
</Barentry>
</Bar>
<C i:nil="true"/>
</UserQuery.Foo>
using this code to test:
void Main()
{
var B=new Bar();
B.Add("aaa","bbb");
var tFoo=new Foo(){Bar=B};
DataContractSerializer ser=new DataContractSerializer(typeof(Foo));
ToXml<Foo>(tFoo).Dump();
}
public static string ToXml<T>(T obj)
{
DataContractSerializer dataContractSerializer = new DataContractSerializer(obj.GetType());
String text;
using (MemoryStream memoryStream = new MemoryStream())
{
dataContractSerializer.WriteObject(memoryStream, obj);
byte[] data = new byte[memoryStream.Length];
Array.Copy(memoryStream.GetBuffer(), data, data.Length);
text = Encoding.UTF8.GetString(data);
}
return text;
}
[System.Runtime.Serialization.DataContract]
public class Foo
{
[System.Runtime.Serialization.DataMember]
public Bar Bar
{ get; set; }
[System.Runtime.Serialization.DataMember]
public string C { get; set; }
}
[CollectionDataContract
(ItemName="Barentry",
KeyName = "A",
ValueName = "B")]
public class Bar:Dictionary<string,string>{
}

Xml serialization - Change the serialization type of xml

I have a struct like this:
public struct Vehicles
{
public string Name { get; set; }
public string Count { get; set; }
public List<Car> Cars { get; set; }
}
public struct Car
{
public string Name { get; set; }
public int Count { get; set; }
public List<Tire> Tires { get; set; }
}
public struct Tire
{
public string Brand { get; set; }
public int Count { get; set; }
public int UniqueCount { get; set; }
public List<Dimension> Dimensions { get; set; }
}
public struct Dimension
{
public string Size { get; set; }
public int AlternateSize { get; set; }
}
When I serialize "Vehicles" it is like:
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org /2001/XMLSchema">
<Vehicles>
<Name>SuperVehicles</Name>
<Cars>
<Car>
<Name>BMW</Name>
<Count>29</Count>
<Tires>
<Tire>
<Name>DMZ</Name>
<Count>26</Count>
<UniqueCount>24</UniqueCount>
<Dimensions>
<Dimension>
<Size>70x570</Size>
<AlternateSize>70x580</AlternateSize>
</Dimension>
<Dimension>
<Size>60x570</Size>
<AlternateSize>60x580</AlternateSize>
</Dimension>
<Dimension>
<Size>50x570</Size>
<AlternateSize>50x580</AlternateSize>
</Dimension>
</Dimensions>
</Tire>
</Tires>
</Car>
</Cars>
</Vehicles>
</root>
Now the problem is, I want to serialize it like this:
<root>
<vehicles vehicleName="superVehicles" vehicleCount="50" carName="BMW"
carCount="25" tireBrand="kamu" tireCount="15" tireUniqueCount="15"
dimensionSize="70x570" dimensionAlternateSize="70x580" />
<vehicles vehicleName="superVehicles" vehicleCount="35" carName="MERCEDES"
carCount="22" tireBrand="kamu" tireCount="12" tireUniqueCount="12"
dimensionSize="60x570" dimensionAlternateSize="60x580" />
<vehicles vehicleName="superVehicles" vehicleCount="35" carName="PORSCHE"
carCount="22" tireBrand="kamu" tireCount="12" tireUniqueCount="12"
dimensionSize="60x570" dimensionAlternateSize="60x580" />
</root>
Do I have to change the structure and avoid the groupings or is there any way to create a schema for xml serialization to gather this result.
Summary:
I get all the child items in a new tag when I serialize the root struct to xml but I need to take them as properties of an instance that create only the count of root (Vehicles in this situation) element of rows to xml.
You need to do manual serialization.
Here is how you can implement this using System.Xml.Linq :
var xmlElementsVehicles = new[]{
new XElement("vehicles ", new object[]
{
new XElement("vehicleName", "superVehicles"),
new XElement("vehicleCount", 35),
new XElement("carName", "PORSCHE"),
new XElement("carCount", 2)
}),
new XElement("vehicles ", new object[]
{
new XElement("vehicleName", "superVehicles"),
new XElement("vehicleCount", 35),
new XElement("carName", "PORSCHE"),
new XElement("carCount", 2)
})
};
var root = new XElement("root", xmlElementsVehicles );
var myXml = new XDocument(new XDeclaration("1.0", "utf-8", "yes"), root);
using (var xmlWriter = XmlWriter.Create(stream))
{
myXml.Save(xmlWriter);
}
To use XmlSerializer the model must roughly be the same as the layout; a few things can change (names, etc). However, your model is nothing like the XML. Three options, then:
create a second DTO model that looks like the XML (you can use xsd.exe on the sample XML to automate this), and use XmlSerializer
don't use XmlSerializer, but build the XML somehow else (XmlDocument or XDocument would be the obvious two, or XmlWriter if the size is very large)
use something like xslt to reshape the XML after writing
There is nothing "easy" can be done to make XmlSerializer write that model into your desired XML.

Categories