I've searched for hours and found similar results but not for this specific scenario. Consider the following XML file.
<root>
<largeImages>
<largeImage>
<url>./imageLarge.jpg</url>
<height>480</height>
<width>640</width>
</largeImage>
</largeImages>
<smallImages>
<smallImage>
<url>./imageSmall.jpg</url>
<height>240</height>
<width>320</width>
</smallImage>
</smallImages>
</root>
What I'm trying to do is deserialize this into a single array of images instead of 2 arrays.
public class root {
[XmlArray("largeImages")]
[XmlArrayItem("largeImage")]
public image[] largeImages { get; set; }
[XmlArray("smallImages")]
[XmlArrayItem("smallImage")]
public image[] smallImages { get; set; }
}
This class gets me 2 arrays. root.largeImages and root.smallImages. Since my application doesn't care about large or small images I'd like to deserialize into the single array root.images. I've tried variations of XmlArray, XmlArrayItem, XmlElement and even XmlChoiceIdentifier without any success. I'm thinking something along the lines of the following which won't compile because apparently the XmlArrayAttribute can only be used once per property.
[XmlArray("largeImages")]
[XmlArray("smallImages")]
[XmlArrayItem("largeImage")]
[XmlArrayItem("smallImage")]
public image[] images { get; set; }
Obviously I could merge the 2 arrays in code after the XML is deserialized but it seems like this should be a simple thing to do.
XPATH is probably your answer assuming you don't really care about having it mapped to a class. XPath wildcards on node name gives an example of how you'd select multiple items - http://csharp.net-tutorials.com/xml/using-xpath-with-the-xmldocument-class/ gives an example of how it's used in C#.
Another way muight be using XSLT: Using the code: How to apply an XSLT Stylesheet in C# and XSLT like Combining elements from 2 lists in XSLT should get you what you want.
Personally I'd go with whatever makes life easiest since it doesn't look like you really care in this example what the intermediate data structure is.
Given that the answer from How to define multiple names for XmlElement field? works primarily for elements not arrays, the easiest solution would seem to be to introduce a surrogate property for one of the image elements, say <smallImages>:
public class root
{
[XmlArray("largeImages")]
[XmlArrayItem("largeImage")]
public List<image> Images { get; set; } = new List<image>();
[XmlArray("smallImages")]
[XmlArrayItem("smallImage")]
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DebuggerBrowsable(DebuggerBrowsableState.Never)]
public List<image> SmallImagesSurrogate { get { return Images; } }
public bool ShouldSerializeSmallImagesSurrogate() { return false; }
}
Notes:
When deserializing to a pre-allocated List<T>, XmlSerializer will simply append deserialized elements to the existing list. That allows elements from both <largeImages> and <smallImages> to be concatenated into the same collection without data loss.
The surrogate property must be public but can be made "less visible" by setting attributes such as [Browsable(false)].
XmlSerializer can successfully deserialize get-only collection properties as long as the collection is pre-allocated. I took advantage of this to avoid adding a setter for the surrogate.
In case you need to re-serialize your root, the method ShouldSerializeSmallImagesSurrogate() will prevent the images array from being double-serialized. (For an explanation of why, see ShouldSerialize*() vs *Specified Conditional Serialization Pattern.) Instead all the images will serialize under <largeImages>. This method does not affect deserialization.
Sample working .Net fiddle.
Simple!!! I do it all the time. The trick is with root that you need to use Elements() and then use FirstOrDefault() to get only one.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
Root root = doc.Elements("root").Select(x => new Root() {
Images = x.Descendants("largeImage").Select(z => new Image() {
url = (string)z.Element("url"),
height = (int)z.Element("height"),
width = (int)z.Element("width")
}).ToList()
}).FirstOrDefault();
root.Images.AddRange(doc.Descendants("smallImage").Select(z => new Image() {
url = (string)z.Element("url"),
height = (int)z.Element("height"),
width = (int)z.Element("width")
}).ToList());
}
}
public class Root
{
public List<Image> Images { get; set; }
}
public class Image
{
public string url { get; set; }
public int height { get; set; }
public int width { get; set; }
}
}
I had a challenge with model serialization, and thanks to MSDN I found the answer. Here is my solution:
public class Document
{
[XmlElement(ElementName = "seller_id")]
public string SellerId { get; set; }
[XmlArray(ElementName = "order_details")]
[XmlArrayItem(Type = typeof(SgtinCode), ElementName = "sgtin")]
[XmlArrayItem(Type = typeof(SsccCode), ElementName = "sscc")]
public Code[] Codes { get; set; }
}
public abstract class Code
{
[XmlText]
public string Value { get; set; }
}
public class SgtinCode : Code
{ }
public class SsccCode : Code
{ }
Model setup:
var document = new Document
{
SellerId = Guid.NewGuid().ToString(),
Codes = new Code[]
{
new SsccCode { Value = "111700126101510000000000011" },
new SsccCode { Value ="111700126101510000000000012" },
new SsccCode { Value ="111700126101510000000000013" },
new SgtinCode { Value = "abc" }
}
}
And XML output:
<?xml version="1.0" encoding="utf-8"?>
<documents>
<foreign_shipment>
<seller_id>fb2d35e7-c5d1-43ad-a272-89f897f41058</seller_id>
<order_details>
<sscc>111700126101510000000000011</sscc>
<sscc>111700126101510000000000012</sscc>
<sscc>111700126101510000000000013</sscc>
<sgtin>abc</sgtin>
</order_details>
</foreign_shipment>
</documents>
Related
Below piece of code is failing and throwing ArgumentException
static void Main(string[] args)
{
string xml = "<root><SourcePatient><Communication>HP:6055550120</Communication></SourcePatient></root>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
var serializedString = JsonConvert.SerializeXmlNode(doc, Newtonsoft.Json.Formatting.None,true);
var deserialise = serializedString.ToObject<SampleModel>();
}
Models are,
public class SampleModel
{
public SourcePatientModel SourcePatient { get; set; }
}
public class SourcePatientModel
{
public List<string> Communication { get; set; }
}
How to deserialize this? Sometimes Communication node from xml string will have multiple entries
Your current xml is only a single entry
<Communication>HP:6055550120</Communication>
Change your xml input
<Communication><Entry>HP:6055550120</Entry></Communication>
So later when you get multiple entries, they can be processed
<Communication><Entry>HP:6055550120</Entry><Entry>HP:xxxxxxxxx</Entry></Communication>
Your class needs tweaked a bit
if a string [] is acceptable
[XmlArray(ElementName = "Communication")]
[XmlArrayItem(ElementName = "Entry")]
public string[] comm_list // Whatever name you want here
{
get; set;
}
// if you want a list here
// also if your going to do this, realize it creates a new list every time you use it, not the best. (bad practice)
List<string> Communication
{
get => new List<string>(comm_list );
}
otherwise it gets a little complicated
[XmlRoot(ElementName="Communication")]
public class Communication // element name by def
{
[XmlElement(ElementName="Entry")]
public List<string> entry { get; set; }
}
Another possibility, not sure how your multiple entries come in.
If multiple entries look like the following
<Communication>HP:6055550120, HP:7055550120</Communication>
Then you cant have a direct list,
public class SourcePatientModel
{
public string Communication { get; set; }
// which again this creates a list everytime, its better to change your xml to match a tag name for each entry
[XmlIgnore]
public List<string> CommunicationValues { get => Communication.Split(',').ToList();
}
Also this is just typed up code, there may be some typos or compile errors
First I parsed xml to the valid model, then you can convert to json if needed
using (TextReader sr = new StringReader(xml))
{
XmlSerializer serializer = new XmlSerializer(typeof(SampleModel));
var schema = (SampleModel)serializer.Deserialize(sr);
}
[Serializable, XmlRoot("root")]
public class SampleModel
{
public SourcePatientModel SourcePatient { get; set; }
}
public class SourcePatientModel
{
[XmlElement("Communication")]
public List<string> Communication { get; set; }
}
I modified your classes to include some XML serialization attributes. (More on how to figure those out later - the short version is that you don't have to figure it out.)
[XmlRoot(ElementName = "SourcePatient")]
public class SourcePatientModel
{
[XmlElement(ElementName = "Communication")]
public List<string> Communication { get; set; }
}
[XmlRoot(ElementName = "root")]
public class SampleModel
{
[XmlElement(ElementName = "SourcePatient")]
public SourcePatientModel SourcePatientModel { get; set; }
}
...and this code deserializes it:
var serializer = new XmlSerializer(typeof(SampleModel));
using var stringReader = new StringReader(xmlString);
SampleModel deserialized = (SampleModel) serializer.Deserialize(stringReader);
Here's a unit test to make sure a test XML string is deserialized with a list of strings as expected. A unit test is a little easier to run and repeat than a console app. Using them makes writing code a lot easier.
[Test]
public void DeserializationTest()
{
string xmlString = #"
<root>
<SourcePatient>
<Communication>A</Communication>
<Communication>B</Communication>
</SourcePatient>
</root>";
var serializer = new XmlSerializer(typeof(SampleModel));
using var stringReader = new StringReader(xmlString);
SampleModel deserialized = (SampleModel) serializer.Deserialize(stringReader);
Assert.AreEqual(2, deserialized.SourcePatientModel.Communication.Count);
}
Here's a key takeaway: You don't need to memorize XML serialization attributes. I don't bother because I find them confusing. Instead, google "XML to Csharp" and you'll find sites like this one. I pasted your XML into that site and let it generate the classes for me. (Then I renamed them so that they matched your question.)
But be sure that you include enough sample data in your XML so that it can generate the classes for you. I made sure there were two Communication elements so it would create a List<string> in the generated class.
Sites like that might not work for extremely complicated XML, but they work for most scenarios, and it's much easier than figuring out how to write the classes ourselves.
I'm truly sorry if the answer exist here under another name but I've been trying to figure this out for a week or so and haven't found anything similar.
So, I'm building an Item system for a game in unity. There is an Item class with these properties
public int ItemId;
public string ItemName;
For simplicity, let's say I want to have two derived classes, Weapon and Armor, with a BaseDamage property for Weapon and BaseArmor for Armor.
I also want to load the items in an ItemContainer class from XML and ideally, from the same XML file rather than one for the weapons, one for armors and one for, say, potions.
I've tried multiple ways but so far the only way I've been able to succeed is by adding the BaseDamage and BaseArmor to the Item base class... like this :
public class Item
{
[XmlAttribute("ID")] public int ItemID;
[XmlElement("Name")] public string ItemName;
[XmlElement("Damage")] public int ItemBaseDamage;
[XmlElement("Armor")] public int ItemBaseArmor;
}
and simply not adding the element to the XML file for some items :
<ItemCollection>
<Items>
<Item ID ="001">
<Name>Dagger</Name>
<Damage>10</Damage>
</Item>
<Item ID ="002">
<Name>Chain Mail</Name>
<Armor>5</Armor>
</Item>
</Items>
</ItemCollection>
It does work, but I feel like this isn't the correct way to do it. Another issue is that if I want to add a Scroll class with a certain function to cast the spell written on that scroll, I need to add the "SpellToCast" property to the base class AND add a CastSpell(Spell) function to it that could be called from any item, which is not what I want...
In short, I'd want to load multiple items from the XML but with each being of their intended derived class so that they get access to their respective functions and get their specific properties such as BaseDamage if it's a weapon.
I've tried to use an XmlElement called ItemClass of type class, but I get an error saying that XmlElement/XmlAttribute is not valid on this declaration type...
I also thought about using an abstract Item class instead but then how do I load the item ID to the abstract base class Item and then BaseDamage to the derived class, Weapon?
This is the code I use to (deserialize? I'm not sure that's the correct term) the XML file :
[XmlRoot("ItemCollection")]
public class ItemContainer
{
[XmlArray("Items")]
[XmlArrayItem("Item")]
public List<Item> items = new List<Item>();
public static ItemContainer Load(string itemPath)
{
TextAsset _xml = Resources.Load<TextAsset>(itemPath);
XmlSerializer serializer = new XmlSerializer(typeof(ItemContainer));
StringReader reader = new StringReader(_xml.text);
ItemContainer items = serializer.Deserialize(reader) as ItemContainer;
reader.Close();
return items;
}
}
So, any help is welcome,
Thanks
Try this code example, a good tool for xml and c# is xml2csharp
class Program
{
static void Main(string[] args)
{
var xml = File.ReadAllText("test.xml");
var serializer = new XmlSerializer(typeof(ItemCollection));
using (var reader = new StringReader(xml))
{
var items = serializer.Deserialize(reader) as ItemCollection;
}
}
}
[XmlRoot(ElementName = "Item")]
public class Item
{
[XmlElement(ElementName = "Name")]
public string Name { get; set; }
[XmlElement(ElementName = "Damage")]
public string Damage { get; set; }
[XmlAttribute(AttributeName = "ID")]
public string ID { get; set; }
[XmlElement(ElementName = "Armor")]
public string Armor { get; set; }
}
[XmlRoot(ElementName = "Items")]
public class Items
{
[XmlElement(ElementName = "Item")]
public List<Item> Item { get; set; }
}
[XmlRoot(ElementName = "ItemCollection")]
public class ItemCollection
{
[XmlElement(ElementName = "Items")]
public Items Items { get; set; }
}
While the first answer wasn't exactly what I was looking for, it did send me on the correct track as I looked into using multiple roots and by googling for that, I fell on a certain website and realized that the solution was simply to tell the XML file that I'm not going to use the Item Class but rather Weapon / Armor / Scroll and such so that they can be considered as their respective derived class.
Did it like this :
[XmlRoot("ItemCollection")]
public class ItemContainer
{
[XmlArray("Items")]
[XmlArrayItem("Weapon", Type = typeof(Weapon))]
[XmlArrayItem("Armor", Type = typeof(Armor))]
public List<Item> items = new List<Item>();
public static ItemContainer LoadItems(string itemPath)
{
TextAsset _xml = Resources.Load<TextAsset>(itemPath);
XmlSerializer serializer = new XmlSerializer(typeof(ItemContainer));
StringReader reader = new StringReader(_xml.text);
ItemContainer items = serializer.Deserialize(reader) as ItemContainer;
reader.Close();
return items;
}
}
I haven't looked at protoBuff, the only thing I found was protocol buffer, which seems to be what you were talking about. I'll keep it in mind but right now it might be a bit too much for my basic understanding of C# in general
<?xml version="1.0" encoding="utf-8" ?>
<ItemCollection>
<Items>
<Weapon Name ="Dagger">
<ID>01</ID>
<BaseDamage>10</BaseDamage>
</Weapon>
<Armor Name ="Chainmail">
<ID>04</ID>
<BaseArmor>5</BaseArmor>
</Armor>
</Items>
</ItemCollection>
I am trying to consume a 3rd party API using ASP.NET C# that returns results as seen in the example below and I am getting tripped up on the fact that the child objects have incremented names:
<Results>
<Count>3</Count>
<Result1>
<Id>1</Id>
<Property1>value</Property1>
<Property2>value</Property2>
...
<PropertyN>value</PropertyN>
</Result1>
<Result2>...properties...</Result2>
<Result3>...properties...</Result3>
</Results>
My C# class is as outlined below, and through some research I am assuming that I have to implement IXmlSerializable to handle this somehow:
public class Results : IXmlSerializable
{
[XmlElement("Count")]
public int Count { get; set; }
public List<Result> ResultItems { get; set; }
}
Is this a common pattern for XML and does anyone have any ideas on how to serialize this? I don't work a lot with XML (mostly JSON), so thanks in advance.
Using xml linq
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication42
{
class Program
{
static void Main(string[] args)
{
string xml =
"<Root>" +
"<Results>" +
"<Count>3</Count>" +
"<Result1>...properties...</Result1>" +
"<Result2>...properties...</Result2>" +
"<Result3>...properties...</Result3>" +
"</Results>" +
"</Root>";
XElement xResults = XElement.Parse(xml);
Results results = xResults.Elements("Results").Select(x => new Results() {
Count = (int)x.Element("Count"),
ResultItems = x.Elements().Where(y => y.Name.LocalName.StartsWith("Result")).Select(y => (string)y).ToList()
}).FirstOrDefault();
}
}
public class Results
{
public int Count { get; set; }
public List<string> ResultItems { get; set; }
}
}
jdweng's answer works, and for those of you who have an option to use that should take it; however, my issue is the data is in a much larger XML response and using the xml serializer instead of XElement works really well with 95% of the fields (the other 5% being the section I specified in the question), so I don't want to jettison that code - instead, I want to implement the IXmlSerializable interface.
After tearing out most of my hair and a little help from this article, I finally figured out how to implement IXmlSerializable for my situation, and I wanted to post the answer for anyone who has a similar issue, as well as community feedback since there didn't seem to be anything on stack overflow about this:
public class Results : IXmlSerializable
{
public int Count { get; set; }
public List<Result> ResultItems { get; set; }
public Results()
{
ResultItems = new List<Result>();
}
public XmlSchema GetSchema()
{
return (null);
}
public void ReadXml(XmlReader reader)
{
reader.ReadStartElement("Results");
if(reader.Name == "Count")
{
Count = reader.ReadElementContentAsInt();
}
for (int i = Count; i > 0; i--)
{
var result = new Result();
reader.ReadStartElement("Result" + i);
result.Property1 = reader.ReadElementContentAsInt();
result.Property2 = reader.ReadElementContentAsString();
...
...
result.PropertyN = reader.ReadElementContentAsString();
ResultItems.Add(result);
}
reader.ReadEndElement();
}
public void WriteXml(XmlWriter writer)
{
//I don't ever need to write this to XML,
//so I'm not going to implement this
throw new NotImplementedException();
}
}
First, I call reader.ReadToElement() and put the element name in there. When the reader gets passed to the ReadXml method, it is at the beginning of the request result, so you need to get it to the beginning of the object you want to serialize.
Then, I read the first element whose name is Count. I put the value in the Count property and then loop through all of the results. It is important to note that you must read every property of the result object, otherwise you will get exceptions.
Lastly, I read the closing tag and move on with my life. Please let me know what you think about this implementation and if there are any improvements that could be made.
One thing I could not figure out is that I have a results object and the reader has a method that I want to use: reader.ReadElementContentAs(typeof(Result), null) - it seems it would be nicer to do that instead of reading each individual node as I have done in my implementation. Does anyone know how to do that?
I have a mongo model like this:
class ObjectA {
[BsonId(IdGenerator = typeof(BsonObjectIdGenerator))]
public BsonObjectId Id;
[BsonElement("number")]
public int Number { get; set; }
[BsonElement("b")]
public List<ObjectB> objectB { get; set; }
}
class ObjectB {
[BsonElement("someProperty")]
public string SomeProperty { get; set; }
}
My problem is when I aggregate the collection with {$unwind:objectB}. The result documencts have a unique object on the property objectB (not a list).
So the cast failes with the exception:
An error occurred while deserializing the ObjectB property of class
ObjectA: Expected element name to be '_t', not
'number'.
Do I have to create a new model for this or is there a easier way to solve it?
You could also choose to work with BsonDocument directly (but that is not strongly typed and more cumbersome to work with), e.g. (I'm using the simple Posts/Tags example here)
var aggregationResults = db.GetCollection("Posts").Aggregate().ResultDocuments;
foreach (var document in aggregationResults)
{
var tag = document.GetValue("Tags").AsString;
}
Unlike the normal query and projection operators, the aggregation framework may change the structure of your document. As you already pointed out, $unwind transforms a document that contains an array into a number of documents that each have a single value of the same name.
Another approach this is to indeed create a new type for this, so
class Post {
public List<string> Tags { get; set; }
...
would become
class PostAggregationResult {
public string Tags { get; set; }
...
That is very easy to work with, but if you have very various aggregation queries, you need a large number of classes which can be annoying.
My app serializes objects in streams.
Here is a sample of what I need :
<links>
<link href="/users" rel="users" />
<link href="/features" rel="features" />
</links>
In this case, the object is a collection of 'links' object.
-----------First version
At first I used the DataContractSerializer, however you cannot serialize members as attributes (source)
Here is the object :
[DataContract(Name="link")]
public class LinkV1
{
[DataMember(Name="href")]
public string Url { get; set; }
[DataMember(Name="rel")]
public string Relationship { get; set; }
}
And here is the result :
<ArrayOflink xmlns:i="...." xmlns="...">
<link>
<href>/users</href>
<rel>users</rel>
</link>
<link>
<href>/features</href>
<rel>features</rel>
</link>
</ArrayOflink>
----------- Second version
Ok, not quiet what I want, so I tried the classic XmlSerializer, but... oh nooo, you cannot specify the name of the root element & of the collection's elements if the root element is a collection...
Here is the code :
[XmlRoot("link")]
public class LinkV2
{
[XmlAttribute("href")]
public string Url { get; set; }
[XmlAttribute("rel")]
public string Relationship { get; set; }
}
Here is the result :
<ArrayOfLinkV2>
<LinkV2 href="/users" rel="users" />
<LinkV2 href="/features" rel="features" />
<LinkV2 href="/features/user/{keyUser}" rel="featuresByUser" />
</ArrayOfLinkV2>
----------- Third version
using XmlSerializer + a root element :
[XmlRoot("trick")]
public class TotallyUselessClass
{
[XmlArray("links"), XmlArrayItem("link")]
public List<LinkV2> Links { get; set; }
}
And its result :
<trick>
<links>
<link href="/users" rel="users" />
<link href="/features" rel="features" />
<link href="/features/user/{keyUser}" rel="featuresByUser" />
</links>
</trick>
Nice, but I don't want that root node !!
I want my collection to be the root node.
Here are the contraints :
the serialization code is generic, it works with anything serializable
the inverse operation (deserialization) have to work too
I don't want to regex the result (I serialize directly in an output stream)
What are my solutions now :
Coding my own XmlSerializer
Trick XmlSerializer when it works with a collection (I tried, having it find a XmlRootElement and plurialize it to generate its own XmlRootAttribute, but that causes problem when deserializing + the items name still keeps the class name)
Any idea ?
What really bother me in that issue, is that what I want seems to be really really really simple...
Ok, here is my final solution (hope it helps someone), that can serialize a plain array, List<>, HashSet<>, ...
To achieve this, we'll need to tell the serializer what root node to use, and it's kind of tricky...
1) Use 'XmlType' on the serializable object
[XmlType("link")]
public class LinkFinalVersion
{
[XmlAttribute("href")]
public string Url { get; set; }
[XmlAttribute("rel")]
public string Relationship { get; set; }
}
2) Code a 'smart-root-detector-for-collection' method, that will return a XmlRootAttribute
private XmlRootAttribute XmlRootForCollection(Type type)
{
XmlRootAttribute result = null;
Type typeInner = null;
if(type.IsGenericType)
{
var typeGeneric = type.GetGenericArguments()[0];
var typeCollection = typeof (ICollection<>).MakeGenericType(typeGeneric);
if(typeCollection.IsAssignableFrom(type))
typeInner = typeGeneric;
}
else if(typeof (ICollection).IsAssignableFrom(type)
&& type.HasElementType)
{
typeInner = type.GetElementType();
}
// yeepeeh ! if we are working with a collection
if(typeInner != null)
{
var attributes = typeInner.GetCustomAttributes(typeof (XmlTypeAttribute), true);
if((attributes != null)
&& (attributes.Length > 0))
{
var typeName = (attributes[0] as XmlTypeAttribute).TypeName + 's';
result = new XmlRootAttribute(typeName);
}
}
return result;
}
3) Push that XmlRootAttribute into the serializer
// hack : get the XmlRootAttribute if the item is a collection
var root = XmlRootForCollection(type);
// create the serializer
var serializer = new XmlSerializer(type, root);
I told you it was tricky ;)
To improve this, you can :
A) Create a XmlTypeInCollectionAttribute to specify a custom root name (If the basic pluralization does not fit your need)
[XmlType("link")]
[XmlTypeInCollection("links")]
public class LinkFinalVersion
{
}
B) If possible, cache your XmlSerializer (in a static Dictionary for example).
In my testing, instanciating a XmlSerializer without the XmlRootAttributes takes 3ms.
If you specify an XmlRootAttribute, it takes around 80ms (Just to have a custom root node name !)
XmlSerializer should be able to do what you need, but it is highly dependent on the initial structure and setup. I use it in my own code to generate remarkably similar things.
public class Links<Link> : BaseArrayClass<Link> //use whatever base collection extension you actually need here
{
//...stuff...//
}
public class Link
{
[XmlAttribute("href")]
public string Url { get; set; }
[XmlAttribute("rel")]
public string Relationship { get; set; }
}
now, serializing the Links class should generate exactly what you are looking for.
The problem with XmlSerializer is when you give it generics, it responds with generics. List implemets Array somewhere in there and the serialized result will nearly always be ArrayOf<X>. To get around that you can name the property, or the class root. The closes to what you need is probably the Second Version from your examples. Im assuming you attempted direct serialization of an object List Links. That wouldn't work because you didn't specify the root node. Now, a similar approach can be found here. In this one they specify the XmlRootAttribute when declaring the serializer. yours would look like this:
XmlSerializer xs = new XmlSerializer(typeof(List<Link>), new XmlRootAttribute("Links"));
Here you go...
class Program
{
static void Main(string[] args)
{
Links ls = new Links();
ls.Link.Add(new Link() { Name = "Mike", Url = "www.xml.com" });
ls.Link.Add(new Link() { Name = "Jim", Url = "www.xml.com" });
ls.Link.Add(new Link() { Name = "Peter", Url = "www.xml.com" });
XmlSerializer xmlSerializer = new XmlSerializer(typeof(Links));
StringWriter stringWriter = new StringWriter();
xmlSerializer.Serialize(stringWriter, ls);
string serializedXML = stringWriter.ToString();
Console.WriteLine(serializedXML);
Console.ReadLine();
}
}
[XmlRoot("Links")]
public class Links
{
public Links()
{
Link = new List<Link>();
}
[XmlElement]
public List<Link> Link { get; set; }
}
[XmlType("Link")]
public class Link
{
[XmlAttribute("Name")]
public string Name { get; set; }
[XmlAttribute("Href")]
public string Url { get; set; }
}