Deserialization of XML file with nested array of elements
I've searched but can't see any helpful examples.
this is my XML sample:
<trans>
<orderNo>0001</orderNo>
<orderDate>08/07/2014</orderDate>
<orders>
<item>
<itemName>item1</itemName>
<itemAmount>200</itemAmount>
<itemMeasures>
<measure>each</measure>
<measure>case</measure>
</itemMeasures>
</item>
<item>
<itemName>item2</itemName>
<itemAmount>100</itemAmount>
<itemMeasures>
<measure>each</measure>
<measure>case</measure>
</itemMeasures>
</item>
</orders>
</trans>
You must create classes for each of the structures you have in the XML and then using XmlSerializer and the method Deserialize of the object from that class you can create nested arrays with the values. If you want code and example, please edit your post with the full xml structure.
See the example below for part of your xml:
[XmlType("trans")]
public class Trans
{
[XmlElement("orderNo")]
public string OrderNo { get; set; }
[XmlElement("orderDate")]
public string OrderDate { get; set; }
[XmlArray("orders")]
public HashSet<Item> Orders { get; set; }
}
[XmlType("item")]
public class Item
{
[XmlElement("itemName")]
public string ItemName { get; set; }
[XmlElement("itemAmount")]
public string ItemAmount { get; set; }
}
The the Deserialization code is:
XmlSerializer mySerializer = new XmlSerializer(typeof(Trans[]), new XmlRootAttribute("trans"));
using (FileStream myFileStream = new FileStream("XmlFile.xml", FileMode.Open))
{
Trans[] r;
r = (Trans[])mySerializer.Deserialize(myFileStream);
}
Related
I am having problems serializing elements of an XML to a list of objects.
This is the XML:
<result>
<stats>
<numitemsfound>1451</numitemsfound>
<startfrom>0</startfrom>
</stats>
<items>
<item>
<id>1</id>
<markedfordeletion>0</markedfordeletion>
<thumbsrc>
</thumbsrc>
<thumbsrclarge>
</thumbsrclarge>
...
<datasource>65</datasource>
<data>
<amount>100</amount>
<kj>389</kj>
<kcal>92.91</kcal>
<fat_gram>0.2</fat_gram>
<fat_sat_gram>-1</fat_sat_gram>
<kh_gram>20.03</kh_gram>
</data>
<servings>
<serving>
<serving_id>386</serving_id>
<weight_gram>150</weight_gram>
</serving>
</servings>
</item>
</result>
The classes I prepared for serialization are
[XmlType("item")]
public class Item
{
[XmlAttribute("id")]
public string id { get; set; }
[XmlAttribute("markedfordeletion")]
public string markedfordeletion { get; set; }
...
[XmlAttribute("datasource")]
public string datasource { get; set; }
[XmlElement("data")]
public Data data { get; set; }
[XmlElement("servings")]
public List<Serving> servings { get; set; }
}
}
This is how I try to serialize the xml
public void ParseSearch(string xml)
{
XmlSerializer serializer = new XmlSerializer(typeof(List<Item>), new XmlRootAttribute("item"));
StringReader stringReader = new StringReader(xml);
var productList = (List<Item>)serializer.Deserialize(stringReader);
}
But I get the error ----> System.InvalidOperationException : <result xmlns=''> was not expected. Can you please help me solve this problem?
You have to use a serializer which serializes an instance of result, not of type List:
XmlSerializer serializer = new XmlSerializer(typeof(Result), new XmlRootAttribute("result")); //whatever `Result` actually is as type).
You canĀ“t serialize and de-serialize just parts of a document, either the whole one or nothing at all.
So you need a root-type:
[XmlRoot("result")]
public class Result
{
public Stats Stats {get; set;}
[XmlArray("items")]
[XmlArrayItem("item")]
public List<Item> Items { get; set; }
}
I am trying to deserialize some XML into an array of items.
Here's the XML:
<?xml version=\"1.0\" encoding=\"utf-8\"?>
<items>
<item>
<name>John</name>
</item>
<item>
<name>Jane</name>
</item>
</items>
And my class:
[XmlRoot("item")]
public class Item
{
[XmlElement("name")]
public string Name { get; set; }
}
I then deserialize:
var xmlSerializer = new XmlSerializer(typeof(Item[]), new XmlRootAttribute("items"));
using (TextReader textReader = new StringReader(xmlString))
{
var items = (Item[])xmlSerializer.Deserialize(textReader);
var itemCount = items.Length;
}
itemCount is 0 (it should be 2).
There is a similar solution here: https://stackoverflow.com/questions/15544517 but it seem to work only when the XML node names are identical to the class names (mine differ in capitalisation).
What do I need to modify to ensure all the items deserialize?
The Xml Root "items" is missing
Your class should be:
[XmlRoot("items")]
public class Items
{
[XmlElement("item")]
public Item[] Item { get; set; }
}
[XmlRoot("item")]
public class Item
{
[XmlElement("name")]
public string Name { get; set; }
}
And the code to deserialize:
var xmlSerializer = new XmlSerializer(typeof(Items), new XmlRootAttribute("items"));
using (TextReader textReader = new StringReader(xmlString))
{
var items = (Items)xmlSerializer.Deserialize(textReader);
var itemCount = items.Item.Length;
}
The root node is <items>, so the Item class should not have the XmlRoot attribute, instead it should use the XmlType attribute:
[XmlType("item")]
public class Item
{
[XmlElement("name")]
public string Name { get; set; }
}
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 {...}
I'm trying to deserialize an XML file to an object array, but I'm receiving empty objects.
My question looks similar to this: How to Deserialize xml to an array of objects? but I can't seem to create a class which inherits IXmlSerializable. That said, I don't think that approach is necessary.
Am I doing something wrong?
File Object
[XmlType("file")]
public class File
{
[XmlElement("id")]
public string Id { get; set; }
[XmlElement("company_name")]
public string Company_Name { get; set; }
[XmlElement("docs")]
public HashSet<doc> Docs { get; set; }
}
Doc Object
[XmlType("doc")]
public class Doc
{
[XmlElement("valA")]
public string ValA { get; set; }
[XmlElement("valB")]
public string ValB { get; set; }
}
XML
<?xml version="1.0" encoding="UTF-8"?>
<files>
<file>
<id>12345</id>
<company_name>Apple</company_name>
<docs>
<doc>
<valA>Info</valA>
<valB>More Info</valB>
</doc>
</docs>
</file>
<file>
<id>12345</id>
<company_name>Microsoft</company_name>
<docs>
<doc>
<valA>Even More Info</valA>
<valB>Lots of it</valB>
</doc>
</docs>
</file>
</files>
Deserialization code
XmlSerializer mySerializer = new XmlSerializer(typeof(File[]), new XmlRootAttribute("files"));
using (FileStream myFileStream = new FileStream("Files.xml", FileMode.Open))
{
File[] r;
r = (File[])mySerializer.Deserialize(myFileStream);
}
You have decorated your properties with XMLAttribute but they are elements in your XML. So, change all XMLAttribute to XmlElement.
[XmlType("file")]
public class File
{
[XmlElement("id")]
public string Id { get; set; }
[XmlElement("company_name")]
public string Company_Id { get; set; }
[XmlArray("docs")]
public HashSet<Doc> Docs { get; set; }
}
[XmlType("doc")]
public class Doc
{
[XmlElement("valA")]
public string ValA { get; set; }
[XmlElement("valB")]
public string ValB { get; set; }
}
Also you XML is not well formed. I guess this is typo though -
<company_name>Apple</company_id>
<company_name>Microsoft</company_id>
Ending tag should be company_name -
<company_name>Apple</company_name>
<company_name>Microsoft</company_name>
I would use xml parser..
XDocument doc=XDocument.Load(url);
File[] r=doc.Elements("file")
.Select(f=>
new File
{
Id=f.Element("id").Value,
Company_Id=f.Element("company_name").Value,
Docs=new HashSet<Docs>(
f.Elements("docs")
.Elements("doc")
.Select(d=>
new Doc
{
ValA=d.Element("valA").Value,
ValB=d.Element("valB").Value
}))
}).ToArray();
Started practicing with XML and C# and I have an error message of "There is an error in XML document (3,2)". After looking at the file, I can't see anything wrong with it (Mind you, I probably missed something since I'm a noob). I'm using a Console Application for C# right now. I'm trying to return a list of Adventurers and just a side note, the GEAR element is optional. Here is what I have so far:
XML File - Test1
<?xml version="1.0" encoding="utf-8"?>
<Catalog>
<Adventurer>
<ID>001</ID>
<Name>John Smith</Name>
<Address>123 Fake Street</Address>
<Phone>123-456-7890</Phone>
<Gear>
<Attack>
<Item>
<IName>Sword</IName>
<IPrice>15.00</IPrice>
</Item>
<Item>
<IName>Wand</IName>
<IPrice>20.00</IPrice>
</Item>
</Attack>
<Defense>
<Item>
<IName>Shield</IName>
<IPrice>5.00</IPrice>
</Item>
</Defense>
</Gear>
</Adventurer>
<Adventurer>
<ID>002</ID>
<Name>Guy noone likes</Name>
<Address>Some Big House</Address>
<Phone>666-666-6666</Phone>
<Gear></Gear>
</Adventurer>
</Catalog>
C# Classes
public class Catalog
{
List<Adventurer> Adventurers { get; set; }
}
public class Adventurer
{
public int ID { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string Phone { get; set; }
public Gear Gear { get; set; }
}
public class Gear
{
public List<Item> Attack { get; set; }
public List<Item> Defense { get; set; }
}
public class Item
{
public string IName { get; set; }
public decimal IPrice { get; set; }
}
Serialize Function - Where the Problem Occurs at Line 5
Catalog obj = null;
string path = #"C:\Users\Blah\Desktop\test1.xml";
XmlSerializer serializer = new XmlSerializer(typeof(Catalog));
StreamReader reader = new StreamReader(path);
obj = (Catalog)serializer.Deserialize(reader);
reader.Close();
Console.ReadLine();
The issue is the list of Adventurers in Catalog:
<?xml version="1.0" encoding="utf-8"?>
<Catalog>
<Adventurers> <!-- you're missing this -->
<Adventurer>
</Adventurer>
...
<Adventurer>
</Adventurer>
</Adventurers> <!-- and missing this -->
</Catalog>
You don't have the wrapping element for the Adventurers collection.
EDIT: By the way, I find the easiest way to build the XML structure and make sure it's compatible is to create the object(s) in C#, then run through the built-in XmlSerializer and use its XML output as a basis for any XML I create rather than forming it by hand.
First, "Adventurers" property is not public, it's inaccessible, I think that the best way to find the error is to serialize your object and then compare the result with your xml file.
Your XML doesn't quite line up with your objects... namely these two...
public string City { get; set; }
and
<Address>123 Fake Street</Address>
Change City to Address or vice versa and it should fix the problem.
Edit: Got this to work in a test project, combination of all our answers...
Add <Adventurers> tag after <Catalog> (and </Adventurers> before </Catalog>) and change
List<Adventurer> Adventurers { get; set; }
to
public List<Adventurer> Adventurers { get; set; }
and it works properly for me.
I was able to get your xml to deserialize with a couple minor changes (namely the public qualifier on Adventurer).
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml.Serialization;
namespace TempSandbox
{
[XmlRoot]
public class Catalog
{
[XmlElement("Adventurer")]
public List<Adventurer> Adventurers;
private readonly static Type[] myTypes = new Type[] { typeof(Adventurer), typeof(Gear), typeof(Item) };
private readonly static XmlSerializer mySerializer = new XmlSerializer(typeof(Catalog), myTypes);
public static Catalog Deserialize(string xml)
{
return (Catalog)Utils.Deserialize(mySerializer, xml, Encoding.UTF8);
}
}
[XmlRoot]
public class Adventurer
{
public int ID;
public string Name;
public string Address;
public string Phone;
[XmlElement(IsNullable = true)]
public Gear Gear;
}
[XmlRoot]
public class Gear
{
public List<Item> Attack;
public List<Item> Defense;
}
[XmlRoot]
public class Item
{
public string IName;
public decimal IPrice;
}
}
I'm using [XmlElement("Adventurer")] because the xml element names don't exactly match the class property names.
NOTE: I'm using a generic deserialization utility i already had on hand .