When I try to deserialize below XML I get error: Settings xmlns='' was not expected.
I have mapped the root node in my class below, why do I get that error?
my xml:
<Settings>
<Access>
<Phone hasTextField="true">
<Item description="CMS" />
</Phone>
</Access>
</Settings>
class
Settings.cs:
[XmlRoot("Settings")]
public class AccessNodes
{
[XmlElement("Access")]
public Access AccessList { get; set; }
}
[XmlType("Access")]
public class Access
{
[XmlElement("Phone")]
public AccessItem Phone { get; set; }
}
public class AccessItem
{
public AccessItem()
{
Items = new List<Item>();
}
[XmlAttribute("hasTextField")]
public bool HasTextField { get; set; }
[XmlElement("Item")]
public List<Item> Items { get; set; }
}
[XmlType("Item")]
public class Item
{
[XmlAttribute("description")]
public string Description { get; set; }
}
SettingsReader.cs
public static class SettingsReader<T>
{
public static T Deserialize(string basePath)
{
string filename = basePath + ".xml";
T t = default(T);
XmlSerializer xs = new XmlSerializer(typeof(T));
using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
t = (T)xs.Deserialize(fs);
}
return t;
}
Call to SettingsReader.cs
Access access = SettingsReader<Access>.Deserialize(Server.MapPath("~/App_Data/access"));
You're trying to deserialize the wrong element - you're trying to deserialize the Access type, whereas your top node is Settings, which is the name applied to the AccessNodes type.
Try this instead:
AccessNodes settings = SettingsReader<AccessNodes>.Deserialize(...);
Related
I'm deserialization the results of a request that has the same tag repeated at multiple levels, I have it working but to do so I'm changing the format of the XML before attempting to deserialize it.
I'm not able to edit the source of the XML to change it to only have Diary at one level.
Is there a way to adjust my XML attributes to handle the deserialization without needing to adjust the response?
XML Response
<?xml version="1.0" ?>
<Root>
<DiaryDetails>
<Diary>
<Diary created_user="value1" created_date="value2" long_text="value3" short_text="value4" entry_type="value5" >Value6</Diary>
</Diary>
<Diary>
<Diary created_user="value7" created_date="value8" long_text="value9" short_text="value10" entry_type="value11" >Value12</Diary>
</Diary>
</DiaryDetails>
</Root>
Class definition
[XmlRoot("DiaryDetails")]
public class Diaries : List<Diary> { }
[XmlRoot("Diary")]
public class Diary
{
[XmlAttribute("created_user")]
public string CreatedBy { get; set; }
[XmlAttribute("created_date")]
public string CreatedDate { get; set; }
[XmlAttribute("long_text")]
public string LongText { get; set; }
[XmlAttribute("short_text")]
public string ShortText { get; set; }
[XmlAttribute("entry_type")]
public string Type { get; set; }
}
Deserialization Method
internal T DeserilaiseObject<T>(string response)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
T DeserilaisedObject;
using (TextReader reader = new StringReader(response))
{
DeserilaisedObject = (T)serializer.Deserialize(reader);
}
return DeserilaisedObject;
}
I'm currently handling this with a string replace:
response = response.Replace("<Diary><Diary", "<Diary").Replace("</Diary></Diary>", "</Diary>");
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApplication40
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XmlReader reader = XmlReader.Create(FILENAME);
XmlSerializer serializer = new XmlSerializer(typeof(Root));
Root root = (Root)serializer.Deserialize(reader);
}
}
[XmlRoot("Root")]
public class Root
{
[XmlArray("DiaryDetails")]
[XmlArrayItem("Diary")]
public List<DiaryMain> diaries { get; set; }
}
public class DiaryMain
{
public Diary Diary { get; set; }
}
[XmlRoot("Diary")]
public class Diary
{
[XmlAttribute("created_user")]
public string CreatedBy { get; set; }
[XmlAttribute("created_date")]
public string CreatedDate { get; set; }
[XmlAttribute("long_text")]
public string LongText { get; set; }
[XmlAttribute("short_text")]
public string ShortText { get; set; }
[XmlAttribute("entry_type")]
public string Type { get; set; }
}
}
Assuming that you are only interested at the attributed Diary elements at the second nesting level you could do this:
// load your xml into a document
var doc = new XmlDocument();
doc.Load("your_xml_file.xml");
// extract the interesting nodes using xpath
var nodes = doc.SelectNodes("//Diary/Diary");
// deserialize the filtered NodeList (yes it's that clunky)
var serializer = new XmlSerializer(typeof(Diary));
var diaries = nodes.Cast<XmlNode>().Select(x => serializer.Deserialize(new XmlNodeReader(x))).Cast<Diary>().ToArray();
I am trying to serialize a C# object into XML so that it could be used as the body of API call. They are very particular about the input they need. I have built the following class to hold the data I need to send over to them. Including attributes and all properties as Elements instead of attributes. They also require that lists include the type="array" I though that creating my own class the implements a List would be the easiest since all lists I give them must have the same attribute. When serialization occurs it serializes the base class of List items but it doesn't include the attribute I want from the derived class.
public class CustomArray<T> : List<T>
{
[XmlAttribute]
public string type { get; set; } = "array";
}
[XmlRoot("message")]
public class MessageBody
{
[XmlArray("Checks"), XmlArrayItem("CheckItem")]
public CustomArray<Check> CheckList { get; set; }
}
public class Check
{
[XmlElement("C_CHECK_NUMBER")]
public string CheckNumber { get; set; }
[XmlElement("C_CHECK_AMOUNT")]
public decimal Amount { get; set; }
[XmlArray("InvoiceList"), XmlArrayItem("Invoice")]
public CustomArray<Invoice> InvoiceList { get; set; }
}
public class Invoice
{
[XmlElement("C_INVOICE_ID")]
public long ID { get; set; }
[XmlElement("C_INVOICE_NUM")]
public string InvoiceNum { get; set; }
}
I then run this code:
// Create a sample object
var message = new MessageBody()
{
CheckList = new CustomArray<Check>
{
new Check
{
CheckNumber = "111",
Amount = 1.00M
},
new Check
{
CheckNumber = "112",
Amount = 2.00M,
InvoiceList = new CustomArray<Invoice>
{
new Invoice
{
ID = 1,
InvoiceNum = "1"
}
}
}
}
};
// Create custom settings
var settings = new XmlWriterSettings
{
OmitXmlDeclaration = true,
Indent = true
};
// Serialize item and print it to console
using (var sw = new StringWriter())
using (var writer = XmlWriter.Create(sw, settings))
{
var serializer = new XmlSerializer(message.GetType());
serializer.Serialize(writer, message, new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty }));
Console.WriteLine(sw.ToString());
}
I get this written to the console:
<message>
<Checks>
<CheckItem>
<C_CHECK_NUMBER>111</C_CHECK_NUMBER>
<C_CHECK_AMOUNT>1.00</C_CHECK_AMOUNT>
</CheckItem>
<CheckItem>
<C_CHECK_NUMBER>112</C_CHECK_NUMBER>
<C_CHECK_AMOUNT>2.00</C_CHECK_AMOUNT>
<InvoiceList>
<Invoice>
<C_INVOICE_ID>1</C_INVOICE_ID>
<C_INVOICE_NUM>1</C_INVOICE_NUM>
</Invoice>
</InvoiceList>
</CheckItem>
</Checks>
</message>
But I need to get this:
<message>
<Checks type="array">
<CheckItem>
<C_CHECK_NUMBER>111</C_CHECK_NUMBER>
<C_CHECK_AMOUNT>1.00</C_CHECK_AMOUNT>
</CheckItem>
<CheckItem>
<C_CHECK_NUMBER>112</C_CHECK_NUMBER>
<C_CHECK_AMOUNT>2.00</C_CHECK_AMOUNT>
<InvoiceList type="array">
<Invoice>
<C_INVOICE_ID>1</C_INVOICE_ID>
<C_INVOICE_NUM>1</C_INVOICE_NUM>
</Invoice>
</InvoiceList>
</CheckItem>
</Checks>
</message>
Thank you for your help!
Here is a dotnetfiddle that I made to show it off. It's not exact but it has the same idea. https://dotnetfiddle.net/ALCX5H
Try following :
[XmlRoot("message")]
public class MessageBody
{
[XmlElement("Checks")]
public Checks Checks { get; set; }
}
public class Checks
{
[XmlAttribute]
public string type { get; set; }
[XmlElement("Checks")]
public List<Check> Checks { get; set; }
}
public class Check
{
[XmlElement("C_CHECK_NUMBER")]
public string CheckNumber { get; set; }
[XmlElement("C_CHECK_AMOUNT")]
public decimal Amount { get; set; }
}
I need to serialize a class to xml. If a certain condition is met at run-time, I want to add an XML attribute to an element and assign it a value. Sometimes, the "Error" attribute will appear and sometimes it won't.
My code that serializes my objects:
public class XmlToolsRepo : IXmlTools
{
public string SerializeToXML<T>(object obj)
{
string results = null;
Encoding enc = Encoding.UTF8;
using (MemoryStream ms = new MemoryStream())
{
using (XmlTextWriter xw = new XmlTextWriter(ms, enc))
{
xw.Formatting = Formatting.None;
XmlSerializerNamespaces emptyNS = new XmlSerializerNamespaces(new[] { new XmlQualifiedName("", "") });
XmlSerializer xSerializer = new XmlSerializer(typeof(T));
xSerializer.Serialize(xw, obj, emptyNS);
}
results = enc.GetString(ms.ToArray());
}
return results;
}
}
A class with a property that could have a new attribute at run-time:
[DataContract]
public class H204
{
[DataMember]
[XmlAttribute]
public string Code { get; set; }
[DataMember]
public string DW { get; set; }
}
When a condition is met I need for the XML to look like this:
<?xml version="1.0" encoding="UTF-8"?>
<H204 Code="A">
<DW Error="test" />
</H204>
Try following :
public class H204
{
[XmlAttribute(AttributeName = "Code")]
public string Code { get; set; }
[XmlElement(ElementName = "DW")]
public DW dw{ get; set; }
}
public class DW
{
[XmlAttribute(AttributeName = "Error")]
public string text { get; set; }
}
I've been looking here for a sollution, but I did not find it in previous answers.
I need to create the following xml with the serialiser
<?xml version="1.0" encoding="Windows-1252"?>
<documents xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<document>
<Keys>
<drawer>GraphicData</drawer>
<somedata>otherData</somedata>
</Keys>
<otherGenericProperties>
<Data>GenericData 2</Data>
</otherGenericProperties>
<Repeat>
<FileInfo mimeType="application/pdf" HREF="PdfFile.pdf" />
</Repeat>
<Repeat>
<FileInfo mimeType="application/pdf" HREF="PdfFile2.pdf" />
</Repeat>
</document>
</documents>
The data consist of a few classes
namespace test
{
public class Documents
{
[XmlElement("Keys")] // this is used so the destination name can change in the future
public Keys keys { get; set; }
}
public class document
{
[XmlElement("Keys")] // this is used so the destination name can change in the future
public Keys keys { get; set; }
[XmlElement("Repeat")] // This does not work
List<Repeat> listRepeat { get; set; }
}
public class Keys
{
[XmlElement("drawer")]
public string drawer { get; set; }
}
public class Repeat
{
[XmlElement("fileInfo")]
public FileInfo fileInfo { get; set; }
}
public class FileInfo
{
public string FileInfo { get; set; }
[XmlAttribute("mimeType")]
public string mimeType { get; set; }
[XmlAttribute("mimeType")]
public string HREF { get; set; }
}
}
the serialiser :
XmlSerializer serializer = new XmlSerializer(typeof(Documents));
using (StreamWriter writer = new StreamWriter(saveBestand, false, xmlEncoding))
{
serializer.Serialize(writer, icm, namespaces);
}
I really need the xm like the example, and also the xml names should be changable by a contract like xmlElement is used for. Somehow the repeat element cant be placed on the level you see in the example. Does anyone have a sollution ?
you have two options.
Option 1
use xsd.exe to generate classes using the xml you want.
xsd yourxmlfile.xml
xsd yourxmlfile.xsd /classes
This will generate classes which you can use for serialization or deserialization.
Option 2:
Paste special option to generate the c# classes.
This does not involve using the command line.
refer blog at: https://dennymichael.net/2014/05/30/convert-xml-to-csharp-classes/comment-page-1/
It seems that you poorly designed your data classes. Try solution below.
public class OtherGenericProperties
{
[XmlElement("Data")]
public string Data { get; set; }
}
[XmlRoot("documents")]
public class Documents
{
[XmlElement("document")]
public Document Document { get; set; }
}
public class Document
{
[XmlElement("Keys")] // this is used so the destination name can change in the future
public Keys Keys { get; set; }
[XmlElement("otherGenericProperties")]
public OtherGenericProperties OtherGenericProperties { get; set; }
[XmlElement("Repeat")] // This does not work
public List<Repeat> ListRepeat { get; set; }
}
public class Keys
{
[XmlElement("drawer")]
public string Drawer { get; set; }
[XmlElement("somedata")]
public string SomeData { get; set; }
}
public class Repeat
{
[XmlElement("FileInfo")]
public FileInfo FileInfo { get; set; }
}
public class FileInfo
{
[XmlAttribute("mimeType")]
public string MimeType { get; set; }
[XmlAttribute("HREF")]
public string Href { get; set; }
}
Serializing:
internal static void Test()
{
var doc = new Documents
{
Document = new Document
{
Keys = new Keys
{
Drawer = "GraphicData",
SomeData = "otherData"
},
OtherGenericProperties = new OtherGenericProperties { Data = "GenericData 2" },
ListRepeat = new List<Repeat>
{
new Repeat { FileInfo =new FileInfo { Href = "PdfFile.pdf", MimeType = "application/pdf" } },
new Repeat { FileInfo = new FileInfo { Href = "PdfFile2.pdf", MimeType = "application/pdf" } }
}
}
};
XmlSerializer serializer = new XmlSerializer(typeof(Documents));
using (var f = new StreamWriter("D:\\doc.xml", false, Encoding.GetEncoding("Windows-1252")))
{
serializer.Serialize(f, doc);
f.Flush();
}
}
Output:
<?xml version="1.0" encoding="Windows-1252"?>
<documents xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<document>
<Keys>
<drawer>GraphicData</drawer>
<somedata>otherData</somedata>
</Keys>
<otherGenericProperties>
<Data>GenericData 2</Data>
</otherGenericProperties>
<Repeat>
<FileInfo mimeType="application/pdf" HREF="PdfFile.pdf" />
</Repeat>
<Repeat>
<FileInfo mimeType="application/pdf" HREF="PdfFile2.pdf" />
</Repeat>
</document>
</documents>
Right now I have a XML file which looks like this :
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfMyMedia xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<MyMedia>
<fileName>C:\Users\Yanis\Pictures\Photos\VID_20130704_203538.mp4</fileName>
<title>VID_20130704_203538.mp4</title>
<length>0</length>
<_type>0</_type>
</MyMedia>
<MyMedia>
<fileName>C:\Users\Yanis\Pictures\Photos\VID_20130802_142038.mp4</fileName>
<title>VID_20130802_142038.mp4</title>
<length>0</length>
<_type>0</_type>
</MyMedia>
</ArrayOfMyMedia>
This XML is generated by this function :
public void WriteXML(List<MyMedia> myMedias)
{
System.Xml.Serialization.XmlSerializer writer = new System.Xml.Serialization.XmlSerializer(typeof(List<MyMedia>));
System.IO.StreamWriter file = new System.IO.StreamWriter(
#"c:\temp\SerializationOverview.xml");
writer.Serialize(file, myMedias);
file.Close();
}
And when I want to retrieve my list of medias of type : List<MyMedias>
With this function :
public void LoadXML()
{
System.Xml.Serialization.XmlSerializer reader = new System.Xml.Serialization.XmlSerializer(typeof(List<MyMedia>));
System.IO.StreamReader file = new System.IO.StreamReader(#"c:\temp\SerializationOverview.xml");
window1.medias = (List<MyMedia>)reader.Deserialize(file);
for (int i = 0; i < window1.medias.Count; i++)
{
window1.mediaList.Items.Add(window1.medias[i]);
}
}
Here is my "MyMedia" class, it's pretty simple though :
public class MyMedia
{
enum type
{
MUSIC,
VIDEO,
IMAGE
};
public String fileName { get; set; }
public String artist { get; set; }
public String title { get; set; }
public int length { get; set; }
public int _type { get; set; }
public MyMedia()
{
}
public override string ToString()
{
return title;
}
}
My window1.medias variable is empty.
Any clue ?
Edit : I found the solution, I had a field in my "MyMedia" class that was not in my .xml file. I removed it and it worked.