Reputation: 387
I have the following xml:
<Applications>
<AccessibleApplication></AccessibleApplication>
<AccessibleApplication></AccessibleApplication>
<EligibleApplication></EligibleApplication>
<EligibleApplication></EligibleApplication>
</Applications>
Is there a way to deserialize this into a C# object so that the AccessibleApplications and EligibleApplications are two separate arrays? I tried the following but get an exception because "Applications" is used more than once.
[XmlArray("Applications")]
[XmlArrayItem("AccessibleApplication")]
public List<Application> AccessibleApplications { get; set; }
[XmlArray("Applications")]
[XmlArrayItem("EligibleApplication")]
public List<Application> EligibleApplications { get; set; }
The exception is: The XML element 'Applications' from namespace '' is already present in the current scope. Use XML attributes to specify another XML name or namespace for the element.
Is this possible to do?
Thanks!
Edit: I forgot to mention that I do not want to have an "Applications" class just for the sake of providing a container object for the two arrays. I have several situations like this and I don't want the clutter of these classes whose only purpose is to split up two arrays of the same type.
I was hoping to be able to deserialize the two arrays into an outer object using some sort of tag like [XmlArrayItem="Application/AccessibleApplication"] without creating an "Applications" class.
Upvotes: 6
Views: 2400
Reputation: 317
You can use this class to create objects from strings, creating strings from objects and create byte [] from objects
StringToObject
var applicationObject = new XmlSerializerHelper<Applications>().StringToObject(xmlString);
ObjectToString
var xmlString = new XmlSerializerHelper<Applications>().ObjectToString(applicationObject);
ObjectToByteArray
var byteArray = new XmlSerializerHelper<Applications>().ObjectToByteArray(applicationObject);
The XmlSerializerHelper:
namespace StackOverflow
{
public class XmlSerializerHelper<T> where T : class
{
private readonly XmlSerializer _serializer;
public XmlSerializerHelper()
{
_serializer = new XmlSerializer(typeof(T));
}
public T ToObject(string xml)
{
return (T)_serializer.Deserialize(new StringReader(xml));
}
public string ToString(T obj, string encoding)
{
using (var memoryStream = new MemoryStream())
{
_serializer.Serialize(memoryStream, obj);
return Encoding.GetEncoding(encoding).GetString(memoryStream.ToArray());
}
}
public byte[] ToByteArray(T obj, Encoding encoding = null)
{
var settings = GetSettings(encoding);
using (var memoryStream = new MemoryStream())
{
using (var writer = XmlWriter.Create(memoryStream, settings))
{
_serializer.Serialize(writer, obj);
}
return memoryStream.ToArray();
}
}
private XmlWriterSettings GetSettings(Encoding encoding)
{
return new XmlWriterSettings
{
Encoding = encoding ?? Encoding.GetEncoding("ISO-8859-1"),
Indent = true,
IndentChars = "\t",
NewLineChars = Environment.NewLine,
ConformanceLevel = ConformanceLevel.Document
};
}
}
}
Your Class:
[XmlRoot]
public class Applications
{
[XmlElement("AccessibleApplication")]
public string[] AccessibleApplication { get; set; }
[XmlElement("EligibleApplication")]
public string[] EligibleApplication { get; set; }
}
Or
[XmlRoot]
public class Applications
{
[XmlElement("AccessibleApplication")]
public List<string> AccessibleApplication { get; set; }
[XmlElement("EligibleApplication")]
public List<string> EligibleApplication { get; set; }
}
Cheers.
Upvotes: 0
Reputation: 6977
You can use XmlElement attribute to deserialize to different lists:
public class Applications
{
[XmlElement("AccessibleApplication")]
public List<Application> AccessibleApplications { get; set; }
[XmlElement("EligibleApplication")]
public List<Application> EligibleApplications { get; set; }
}
public class Application
{
[XmlText]
public string Value { get; set; }
}
So for a sample XML:
<Applications>
<AccessibleApplication>xyz</AccessibleApplication>
<AccessibleApplication>abc</AccessibleApplication>
<EligibleApplication>def</EligibleApplication>
<EligibleApplication>zzz</EligibleApplication>
</Applications>
The following snippet would output the below:
using (var reader = new StreamReader("XMLFile1.xml"))
{
var serializer = new XmlSerializer(typeof(Applications));
var applications = (Applications)serializer.Deserialize(reader);
Console.WriteLine("AccessibleApplications:");
foreach (var app in applications.AccessibleApplications)
{
Console.WriteLine(app.Value);
}
Console.WriteLine();
Console.WriteLine("EligibleApplications:");
foreach (var app in applications.EligibleApplications)
{
Console.WriteLine(app.Value);
}
}
Output:
AccessibleApplications:
xyz
abc
EligibleApplications:
def
zzz
Upvotes: 0
Reputation: 897
I've found a fairly neat way to do this, first make a class like this:
using System.Xml.Serialization;
[XmlRoot]
public class Applications
{
[XmlElement]
public string[] AccessibleApplication;
[XmlElement]
public string[] EligibleApplication;
}
Notice how the elements are individual arrays. Now using this class (I had my XML in a separate file hence the XmlDocument class).
var doc = new XmlDocument();
doc.Load("../../Apps.xml");
var serializer = new XmlSerializer(typeof(Applications));
Applications result;
using (TextReader reader = new StringReader(doc.InnerXml))
{
result = (Applications)serializer.Deserialize(reader);
}
Now to prove this works you can write this all in to a console app and do a foreach to print all the values in your arrays, like so:
foreach (var app in result.AccessibleApplication)
{
Console.WriteLine(app);
}
foreach (var app in result.EligibleApplication)
{
Console.WriteLine(app);
}
Upvotes: 1