I have found a solution for handling circular reference when using xml serialization. But in my case I have a List:
public class Category
{
public Category()
{
Items = new List<CategoryItem>();
}
public string CategoryName { get; set; }
public List<CategoryItem> Items { get; set; }
}
and:
public class CategoryItem
{
public string Link { get; set; }
public Category Category { get; set; }
}
Program:
private static void Main(string[] args)
{
var programmingCategory = new Category {CategoryName = "Programming"};
var ciProgramming = new CategoryItem
{
Link = "www.stackoverflow.com",
Category = programmingCategory
};
var fooCategory = new CategoryItem
{
Category = programmingCategory,
Link = "www.foo.com"
};
programmingCategory.Items.Add(ciProgramming);
programmingCategory.Items.Add(fooCategory);
var serializer = new XmlSerializer(typeof (Category));
var file = new FileStream(FILENAME, FileMode.Create);
serializer.Serialize(file, programmingCategory);
file.Close();
}
I always get an
InvalidOperationException
How can I solve this?
You just change CategoryItem model
public class CategoryItem
{
public string Link { get; set; }
}
Modify this code :
private static void Main(string[] args)
{
var programmingCategory = new Category {CategoryName = "Programming"};
var ciProgramming = new CategoryItem
{
Link = "www.stackoverflow.com"
};
var fooCategory = new CategoryItem
{
Link = "www.foo.com"
};
programmingCategory.Items.Add(ciProgramming);
programmingCategory.Items.Add(fooCategory);
var serializer = new XmlSerializer(typeof (Category));
var file = new FileStream(FILENAME, FileMode.Create);
serializer.Serialize(file, programmingCategory);
file.Close();
}
i think it's work fine.Please try this code. I just change your model and get this output.
<?xml version="1.0"?>
-<Category xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<CategoryName>Programming</CategoryName>
-<Items>
-<CategoryItem>
<Link>www.stackoverflow.com</Link>
</CategoryItem>
-<CategoryItem>
<Link>www.foo.com</Link>
</CategoryItem>
</Items>
</Category>
Related
I have complex class which I want to serialize to XML format using costum attributes. I am stucked at XMLelement which is List and I would like to generate new items with constructor, where I can fill attribute name and text value.
Now I have to create seperate objects and those I can add to the List. I want to simplify this.
class to be serialized:
[XmlElement("Cfg")]
public ElCfg Cfg = new ElCfg();
public class ElCfg
{
[XmlAttribute("Name")] public string CfgName { get; set; } = "Default";
[XmlElement("Content")] public ElCont Content = new ElCont();
}
public class ElCont
{
[XmlAttribute("ver")] public string ContentVer { get; set; }
[XmlElement("Prop")] public List<ElProp> Properties = new List<ElProp>();
}
public class ElProp
{
[XmlAttribute("Name")]
public string PropertyName { get; set; }
[XmlText]
public string PropertyVal { get; set; }
}
usage in main:
static void Main(string[] args)
{
//build promotic object
PromoticXML xmlDoc = new PromoticXML();
xmlDoc.Cfg.Content.ContentVer = "80323";
PromoticXML.ElProp prop1 = new PromoticXML.ElProp();
prop1.PropertyName = "neco";
prop1.PropertyVal = "necojineho";
PromoticXML.ElProp prop2 = new PromoticXML.ElProp();
prop2.PropertyName = "neco";
prop2.PropertyVal = "necojineho";
xmlDoc.Cfg.Content.Properties.Add(prop1);
xmlDoc.Cfg.Content.Properties.Add(prop2);
//serialize promotic object
XmlWriterSettings xmlSet = new XmlWriterSettings();
xmlSet.Encoding = Encoding.Unicode;
xmlSet.Indent = true;
xmlSet.IndentChars = " ";
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
XmlSerializer serializer = new XmlSerializer(typeof(PromoticXML));
using (XmlWriter writer = XmlWriter.Create("promotic.xml", xmlSet))
{
serializer.Serialize(writer, xmlDoc);
}
Process.Start("notepad.exe", "promotic.xml");
}
What my goal is:
xmlDoc.Cfg.Content.Properties.Add(new PromoticXML.ElProp("someName", "someText"));
instead of:
PromoticXML.ElProp prop1 = new PromoticXML.ElProp();
prop1.PropertyName = "neco";
prop1.PropertyVal = "necojineho";
xmlDoc.Cfg.Content.Properties.Add(prop1);
I'm trying to create a XML something like this :
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
- <inventory_report:inventoryReportMessage xmlns:inventory_report="urn:gs1:ecom:inventory_report:xsd:3" xmlns:sh="http://www.unece.org/cefact/namespaces/StandardBusinessDocumentHeader" xmlns:ecom_common="urn:gs1:ecom:ecom_common:xsd:3" xmlns:shared_common="urn:gs1:shared:shared_common:xsd:3">
- <sh:StandardBusinessDocumentHeader>
<sh:HeaderVersion>Standard Business Header version 1.3</sh:HeaderVersion>
- <sh:Sender>
<sh:Identifier Authority="GS1">0000</sh:Identifier>
- <sh:ContactInformation>
<sh:Contact>some one</sh:Contact>
<sh:EmailAddress>someone#example.com</sh:EmailAddress>
<sh:TelephoneNumber>00357</sh:TelephoneNumber>
<sh:ContactTypeIdentifier>IT Support</sh:ContactTypeIdentifier>
</sh:ContactInformation>
</sh:Sender>
I'm using the below code for creating the XML -->
var xelementNode = doc.CreateElement("inventory_report", "inventoryReportMessage","urn:gs1:ecom:inventory_report:xsd:3");
doc.AppendChild(xelementNode);
var xelementSubNode = doc.CreateElement("sh", xelementNode, "StandardBusinessDocumentHeades","");
xelementNode.AppendChild(xelementSubNode);
I'm getting this output for the above code -->
<?xml version="1.0" encoding="ISO-8859-1" standalone="yes" ?>
- <inventory_report:inventoryReportMessage xmlns:inventory_report="urn:gs1:ecom:inventory_report:xsd:3">
- <StandartBusinessDocumentHeader>
<HeaderVersion>Standard Business Header Version 1.3</HeaderVersion>
- <Sender>
<Identifier>GS1</Identifier>
- <ContactInformation>
<Contact>Turkey IT Support</Contact>
<EmailAddress>someone#example.com</EmailAddress>
<TelephoneNumber>00 13</TelephoneNumber>
<ContactTypeIdentifier>IT Support</ContactTypeIdentifier>
</ContactInformation>
</Sender>
</StandartBusinessDocumentHeader>
</inventory_report:inventoryReportMessage>
The second prefix ("sh") doesn't work. Can someone help me???
For serialization approach, you can define classes:
public class ContactInformation
{
[XmlElement(ElementName = "Contact")]
public string Contact { get; set; }
[XmlElement(ElementName = "EmailAddress")]
public string EmailAddress { get; set; }
[XmlElement(ElementName = "TelephoneNumber")]
public string TelephoneNumber { get; set; }
[XmlElement(ElementName = "ContactTypeIdentifier")]
public string ContactTypeIdentifier { get; set; }
}
public class Identifier
{
[XmlAttribute("Authority")]
public string Authority { get; set; }
[XmlText]
public string Value { get; set; }
}
public class Sender
{
[XmlElement(ElementName = "Identifier")]
public Identifier Identifier { get; set; }
[XmlElement(ElementName = "ContactInformation")]
public ContactInformation ContactInformation { get; set; }
}
public class StandartBusinessDocumentHeader
{
[XmlElement(ElementName = "HeaderVersion")]
public string HeaderVersion { get; set; }
[XmlElement(ElementName = "Sender")]
public Sender Sender { get; set; }
}
[XmlRoot(ElementName = "inventoryReportMessage", Namespace = "urn:gs1:ecom:inventory_report:xsd:3")]
public class InventoryReportMessage
{
[XmlElement("StandardBusinessDocumentHeader", Namespace = "http://www.unece.org/cefact/namespaces/StandardBusinessDocumentHeader")]
public StandartBusinessDocumentHeader Header { get; set; }
}
then serialize those as below:
var report = new InventoryReportMessage
{
Header = new StandartBusinessDocumentHeader {
HeaderVersion = "Standard Business Header version 1.3",
Sender = new Sender
{
Identifier = new Identifier
{
Authority = "GS1",
Value = "0000"
},
ContactInformation = new ContactInformation
{
Contact = "some one",
EmailAddress = "someone#example.com",
TelephoneNumber = "00357",
ContactTypeIdentifier = "IT Support"
}
}
}
};
using (var stream = new MemoryStream())
{
using (var writer = new StreamWriter(stream))
{
var settings = new XmlWriterSettings {
Indent = true
};
using (var xmlWriter = XmlWriter.Create(writer, settings))
{
xmlWriter.WriteStartDocument(false);
var serializer = new XmlSerializer(typeof(InventoryReportMessage));
var namespaces = new XmlSerializerNamespaces();
namespaces.Add("inventory_report", "urn:gs1:ecom:inventory_report:xsd:3");
namespaces.Add("sh", "http://www.unece.org/cefact/namespaces/StandardBusinessDocumentHeader");
namespaces.Add("ecom_common", "urn:gs1:ecom:ecom_common:xsd:3");
namespaces.Add("shared_common", "urn:gs1:shared:shared_common:xsd:3");
serializer.Serialize(xmlWriter, report, namespaces);
}
stream.Position = 0;
using (var reader = new StreamReader(stream))
{
Console.WriteLine(reader.ReadToEnd());
}
}
}
Console.ReadLine();
Using xml linq. I like to create a string header and then add dynamic values in code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string header =
"<inventory_report:inventoryReportMessage xmlns:inventory_report=\"urn:gs1:ecom:inventory_report:xsd:3\" xmlns:sh=\"http://www.unece.org/cefact/namespaces/StandardBusinessDocumentHeader\" xmlns:ecom_common=\"urn:gs1:ecom:ecom_common:xsd:3\" xmlns:shared_common=\"urn:gs1:shared:shared_common:xsd:3\">" +
"<sh:StandardBusinessDocumentHeader>" +
"<sh:HeaderVersion>Standard Business Header version 1.3</sh:HeaderVersion>" +
"<sh:Sender>" +
"</sh:Sender>" +
"</sh:StandardBusinessDocumentHeader>" +
"</inventory_report:inventoryReportMessage>";
XDocument doc = XDocument.Parse(header);
XElement sender = doc.Descendants().Where(x => x.Name.LocalName == "Sender").FirstOrDefault();
XNamespace shNs = sender.GetNamespaceOfPrefix("sh");
sender.Add(new XElement(shNs + "Identifier", new object[] {
new XAttribute("Authority", "GS1"),
"0000"
}));
sender.Add( new XElement(shNs + "ContactInformation", new object[] {
new XElement(shNs + "Contact", "some one"),
new XElement(shNs + "EmailAddress", "someone#example.com"),
new XElement(shNs + "TelephoneNumber", "00357"),
new XElement(shNs + "ContactTypeOdemtofier", "IT Support")
}));
}
}
}
I'm trying to add schemaLocation attribute to XML root element when serializing List<T>. Code works fine if I'm serializing just one object but does not work on lists. My current code:
public class SomeObject
{
public int Id { get; set; }
public string Name { get; set; }
}
public class XmlListContainer<T> : List<T>
{
[XmlAttribute(Namespace = XmlSchema.InstanceNamespace)]
public string schemaLocation = "http :// localhost/someschema";
}
public class BuildXml
{
public static void GetXml()
{
var list = new XmlListContainer<SomeObject>()
{
new SomeObject() { Id = 1, Name = "One" },
new SomeObject() { Id = 2, Name = "Two" },
};
var objectToXml = list;
string output;
using (var writer = new StringWriter())
{
var xs = new XmlSerializer(objectToXml.GetType());
var nameSpaces = new XmlSerializerNamespaces();
nameSpaces.Add("xsi", "http :// www.w3.org/2001/XMLSchema-instance");
xs.Serialize(writer, objectToXml, nameSpaces);
output = writer.GetStringBuilder().ToString();
writer.Close();
}
Console.WriteLine(output);
}
}
XML root element appears without schemaLocation:
<ArrayOfSomeObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
If I'm changing code to
public class SomeObject
{
public int Id { get; set; }
public string Name { get; set; }
[XmlAttribute(Namespace = XmlSchema.InstanceNamespace)]
public string schemaLocation = "http :// localhost/someschema";
}
...
var objectToXml = new SomeObject() { Id = 1, Name = "One" };
...all looks fine but I need list list
<SingleObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://localhost/someschema">
Is it possible to add schemaLocation attribute when serializing List<T>?
I have this item Class :
public class Movie
{
public string VideoId { get; set; }
public string Title { get; set; }
}
And i have List<Movie> of this items and i use this code to Serialize to xml file:
string fileName = index + ".xml";
string serializationFile = Path.Combine(dir, fileName);
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
using (var writer = XmlWriter.Create(serializationFile, settings))
{
var serializer = new XmlSerializer(typeof(List<Movie>));
serializer.Serialize(writer, tmpList);
}
And this is the result:
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfMovie xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Movie>
<VideoId>MyId</VideoId>
<Title>MyTitle</Title>
</Movie>
<Movie>
<VideoId>MyId1</VideoId>
<Title>MyTitle1</Title>
</Movie>
<Movie>
<VideoId>MyId2</VideoId>
<Title>MyTitle2</Title>
</Movie>
<Movie>
<VideoId>MyId3</VideoId>
<Title>MyTitle3</Title>
</Movie>
</ArrayOfMovie>
And it this possible to add attribute to the ArrayOfMovie node,something like this:
<ArrayOfMovie xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" customattribute='Yes'>
Yes, you can do this using the XmlAttribute attribute. In order to do this, you need to define your custom attribute. It comes with the price of one more class that represents the array (nested in the root node). If you have no problem with this addition, then the solution can look like this:
public class ArrayOfMovie
{
// define the custom attribute
[XmlAttribute(AttributeName="CustomAttribute")]
public String Custom { get; set; }
// define the collection description
[XmlArray(ElementName="Items")]
public List<Movie> Items { get; set; }
}
public class Movie
{
public string VideoId { get; set; }
public string Title { get; set; }
}
Then create, fill and serialize as you already do - the one new thing is to fill your custom attribute:
// create and fill the list
var tmpList = new List<Movie>();
tmpList.Add(new Movie { VideoId = "1", Title = "Movie 1" });
tmpList.Add(new Movie { VideoId = "2", Title = "Movie 2" });
// create the collection
var movies = new ArrayOfMovie
{
Items = tmpList,
Custom = "yes" // fill the custom attribute
};
// serialize
using (var writer = XmlWriter.Create(serializationFile, settings))
{
var serializer = new XmlSerializer(typeof(ArrayOfMovie));
serializer.Serialize(writer, movies);
}
The XML output looks like this:
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfMovie xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
CustomAttribute="yes">
<Items>
<Movie>
<VideoId>1</VideoId>
<Title>Movie 1</Title>
</Movie>
<Movie>
<VideoId>2</VideoId>
<Title>Movie 2</Title>
</Movie>
</Items>
</ArrayOfMovie>
You could do it after serialization. The code skeleton looks like:
using (MemoryStream ms = new MemoryStream())
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
using (var writer = XmlWriter.Create(ms, settings))
{
var serializer = new XmlSerializer(typeof(List<Movie>));
serializer.Serialize(writer, tmpList);
}
ms.Position = 0;
XDocument doc = XDocument.Load(new XmlTextReader(ms));
doc.Root.Add(new XAttribute("customAttribute", "Yes"));
doc.Save(filename);
}
You would want to wrap the List<Movie> inside a class and then serialize that.
Something like the following
class Program
{
static void Main(string[] args)
{
string fileName = "abcd2.xml";
string serializationFile = Path.Combine(#"C:\", fileName);
List<Movie> tmpList = new List<Movie>();
tmpList.Add(new Movie() { VideoId = "1", Title = "Hello" });
tmpList.Add(new Movie() { VideoId = "2", Title = "ABCD" });
MovieList list = new MovieList("Yes", tmpList);
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
using (var writer = XmlWriter.Create(serializationFile, settings))
{
var serializer = new XmlSerializer(typeof(MovieList));
serializer.Serialize(writer, list);
}
}
}
public class MovieList
{
private string custom;
private List<Movie> movies;
public MovieList() { }
public MovieList(string custom, List<Movie> movies)
{
this.movies = movies;
this.custom = custom;
}
[XmlAttribute]
public string CustomAttribute
{
get { return this.custom; }
set { this.custom = value; }
}
public List<Movie> Movies
{
get
{
return movies;
}
set
{
this.movies = value;
}
}
}
public class Movie
{
public string VideoId { get; set; }
public string Title { get; set; }
}
The code can be improved a lot. This is just an example snippet. Check out the following MSDN link: http://msdn.microsoft.com/en-us/library/58a18dwa(v=vs.110).aspx
i have two list of elements with same length eg.
List 1: profile1, profile2,profile3
List 2: 1,0,1
these lists are the public property in class objects.
i.e:
class Serviceinfo
{
[xmlArray("Profiles")]
[xmlArrayItem("Profile")]
public list<string> Profiles;
public list<int> state;
}
here i need to map each profile with its state. eg.
<serviceinfo>
<profiles>
<profile>profile1</profile>
<state>1</state>
</profiles>
<profiles>
<profile>profile2</profile>
<state>0</state>
</profiles>
<profiles>
<profile>profile3</profile>
<state>1</state>
</profiles>
</serviceinfo>
how do i change my class object, to return the above xml result. is it possible to get the above output in xml serialization method.
I'm not sure if it can be done using XmlSerializer because your desired XML structure is quite strange when compared with your class.
But it definitely can be done using LINQ to XML:
var serviceInfo = new Serviceinfo { Profiles = new List<string> { "one", "two", "three" }, state = new List<int> { 1, 2, 4 } };
var xml = new XDocument(
new XElement("serviceinfo",
serviceInfo.Profiles
.Zip(serviceInfo.state, (p, s) => new { p, s })
.Select(x =>
new XElement("profiles",
new XElement("profile", x.p),
new XElement("state", x.s.ToString())))));
If you really want to XML Serialization you should change your class structure to
[XmlRoot(ElementName = "serviceInfo")]
public class Serviceinfo
{
[XmlElement("profiles")]
public List<Profile> Profiles { get; set; }
}
public class Profile
{
[XmlElement(ElementName = "profile")]
public string Name { get; set; }
[XmlElement(ElementName = "state")]
public int State { get; set; }
}
and use XmlSerializer:
var serviceInfo = new Serviceinfo
{
Profiles = new List<Profile>() {
new Profile { Name = "one", State = 1 },
new Profile { Name = "two", State = 2 }
}
};
var writer = new StringWriter();
var serializer = new XmlSerializer(typeof(Serviceinfo));
serializer.Serialize(writer, serviceInfo);
var xml = writer.ToString();
#Gomathipriya : As per what I understand from your problem, the best solution would be create one single collection with both the values as properties as mentioned in the below example and then convert the entire collection to XML.
convert the Collection to XML : http://www.dotnetcurry.com/showarticle.aspx?ID=428
Sample C# Code:
class Program
{
public static void Main(string[] args)
{
List<string> Profiles = new List<string>();
List<int> state = new List<int>();
// Just filling the entities as per your needs
for (int i = 0; i < 5; i++)
{
Profiles.Add("P-" + i.ToString());
state.Add(i);
}
listOfProfileState ProfileStateColl = new listOfProfileState();
for (int i = 0; i < Profiles.Count; i++)
{
ProfileStateColl.Add(new ProfileState() { Profile = Profiles[i], State = state[i] });
}
}
}
public class ProfileState
{
public string Profile { get; set; }
public int State { get; set; }
}
public class listOfProfileState : List<ProfileState>
{
}
as per the above mentioned example if you convert the collection 'ProfileStateColl' to XML you will have your solution that you need. :)