I'm not experienced in XML-serialization. I need to serialize System.Collections.Generic.List to XML document. I have the following classes:
public class Person
{
public string Name;
public string Phone;
public Int32 Score;
}
[Serializable()]
public class PersonOperation:Person
{
public String City;
public String OperationType;
public DateTime OperationDate;
public Decimal Amount;
public Decimal AmountEUR;
public void RoubleToEuro(CurrencyCode p_CurrencyCode, Decimal p_CurrencyRate)
{
if (p_CurrencyCode == CurrencyCode.Euro)
{
this.AmountEUR = Decimal.Round(Amount / p_CurrencyRate, 2);
}
}
}
I have a collection of PersonOperation instances that I must serialize to XML.
private List<PersonOperation> _depositorsOperationsList = new List<PersonOperation>();
For XML serialization I try to use the following method:
public XmlDocument GetEntityXml<T>()
{
XmlAttributeOverrides overrides = new XmlAttributeOverrides();
XmlAttributes attr = new XmlAttributes();
attr.XmlRoot = new XmlRootAttribute("Operation");
overrides.Add(typeof(List<T>), attr);
XmlDocument xmlDoc = new XmlDocument();
XPathNavigator nav = xmlDoc.CreateNavigator();
using (XmlWriter writer = nav.AppendChild())
{
XmlSerializer ser = new XmlSerializer(typeof(List<T>), overrides);
ser.Serialize(writer, _depositorsOperationsList);
}
return xmlDoc;
}
I'm in need of the following XML-format after serialization:
<?xml version="1.0" encoding="Windows-1251" ?>
<Operation>
<PersonOperation>
<Name>John Smith</Name>
<Phone>79161234586</Phone>
<City>Glasgow</City>
<Date>2014-02-03</Date>
<OperationType>Join</OperationType>
<Amount>9000.00</Amount>
<AmountEUR>144.06</AmountEUR>
</PersonOperation>
<PersonOperation>
<Name>Bill Satly</Name>
<Phone>79163214569</Phone>
<City>London</City>
<Date>2014-07-10</Date>
<OperationType>Join</OperationType>
<Amount>9000.00</Amount>
<AmountEUR>144.06</AmountEUR>
</PersonOperation>
. . . . . . . . . . .
<Operation>
But instead of this format I have the following one-line horror:
<Operation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><PersonOperation><Name>John Smith</Name><Phone>79161234586</Phone><Score>270</Score><City>Glasgow</City><OperationType>Join</OperationType><OperationDate>2014-02-03</OperationDate><Amount>9000.0000</Amount><AmountEUR>144.06</AmountEUR></PersonOperation><PersonOperation><Name>Bill Satly</Name><Phone>79163214569</Phone><Score>270</Score><City>London</City><OperationType>Join</OperationType><OperationDate>2014-07-10</OperationDate><Amount>9000.0000</Amount><AmountEUR>144.06</AmountEUR></PersonOperation></Operation>
How can I repair my GetEntityXml method for correct XML-format?
The XmlWriter has a Settings property of type XmlWriterSettings.
Try using that to specify the formatting to be used.
using (XmlWriter writer = nav.AppendChild())
{
writer.Settings.Indent = true;
XmlSerializer ser = new XmlSerializer(typeof(List<T>), overrides);
ser.Serialize(writer, _depositorsOperationsList);
}
More information here:
https://msdn.microsoft.com/en-us/library/kbef2xz3(VS.80).aspx
If you open your file with special XML editor or just with web navigator like chrome or internet explorer it will look like you want.
Just pasting snippet from my code that works fine..
Public Function ToXmlString() As String
Dim builder = New StringBuilder()
Dim xmlSerializer = New XmlSerializer(GetType(List(Of T)), New XmlRootAttribute(_rootNodeName))
Using writer = XmlWriter.Create(builder, New XmlWriterSettings() With {.OmitXmlDeclaration = True})
xmlSerializer.Serialize(writer, _source)
End Using
Return builder.ToString()
End Function
---- Converted C# Code ----
public string ToXmlString()
{
var builder = new StringBuilder();
var xmlSerializer = new XmlSerializer(typeof(List<T>), new XmlRootAttribute(_rootNodeName));
using (writer = XmlWriter.Create(builder, new XmlWriterSettings { OmitXmlDeclaration = true })) {
xmlSerializer.Serialize(writer, _source);
}
return builder.ToString();
}
where _rootNodeName is name of your root node of xml and _source is sourceList
And then to create XMLDoc from string --
XmlDocument xml = new XmlDocument();
xml.LoadXml(xmlString);
Related
following is the part of my xml serializing object.
private decimal tOAMOUNTField;
public decimal TOAMOUNT
{
get
{
return this.tOAMOUNTField;
}
set
{
this.tOAMOUNTField = value;
}
}
XmlSerializer xsSubmit = new XmlSerializer(typeof(MyClassObject));
var entity = new Myobject();
entity .TOAMOUNT = 2.22M;
using (StringWriter sww = new StringWriter())
{
using (XmlWriter writer = XmlWriter.Create(sww))
{
// sww.WriteLine(#"<?xml version=""1.0"" encoding=""UTF-8""?>");
xsSubmit.Serialize(writer , entity);
output = sww.ToString();
}
}
above mention "ToAmount" Property is not serializing in XML
Kindly point out the mistake because all other properties are serializing
You are initializing a XmlSerializer object with type MyClassObject.
XmlSerializer xsSubmit = new XmlSerializer(typeof(MyClassObject));
But are serializing a 'Myobject()' object.
Try changing it in:
XmlSerializer xsSubmit = new XmlSerializer(typeof(Myobject));
I have that XML file which looks like this:
<?xml version="1.0" encoding="utf-8"?>
<backupatmail>
<backup id="0">
<foldername>TestFolder</foldername>
<backupdate>09/10/2015</backupdate>
<comment>Sample comment text is here</comment>
<numberofparts>7</numberofparts>
<lastsucceed>Test.007</lastsucceed>
</backup>
<backup id="1">
<foldername>TestFolder2</foldername>
<backupdate>09/10/2015</backupdate>
<comment>Sample comment text is here</comment>
<numberofparts>15</numberofparts>
<lastsucceed>Test.015</lastsucceed>
</backup>
</backupatmail>
Now, I want to append new node(?):
<backup id="999">
<foldername>testing1</foldername>
<backupdate>99/99/9999</backupdate>
</backup>
I wrote following code:
public static void AddBackupToXML()
{
XmlDocument doc = new XmlDocument();
doc.Load(GlobalSettings.appDefaultFolder + "backups.xml");
XmlElement backupNodeNew = doc.CreateElement("backup");
XmlAttribute backupId = doc.CreateAttribute("id");
backupId.Value = "999";
backupNodeNew.Attributes.Append(backupId);
XmlNode nodeTitle = doc.CreateElement("foldername");
nodeTitle.InnerText = "testing1";
XmlNode nodeUrl = doc.CreateElement("backupdate");
nodeUrl.InnerText = "99/99/9999";
backupNodeNew.AppendChild(nodeTitle);
backupNodeNew.AppendChild(nodeUrl);
doc.DocumentElement.AppendChild(backupNodeNew);
doc.Save(GlobalSettings.appDefaultFolder + "backups.xml");
}
Is there any shorten way to do that and also keep simplicity at beginners level?
I will recommend you to use LINQ to XML. It has more simple API for working with XML and your code will look like
var file_name = GlobalSettings.appDefaultFolder + "backups.xml";
XDocument xdoc = XDocument.Load(file_name);
var backup999 = new XElement("backup",
new XAttribute("id", 999),
new XElement("foldername", "testing1"),
new XElement("backupdate", "99/99/9999")
);
xdoc.Root.Add(backup999);
xdoc.Save(file_name);
How I did it plenty of times, using copy special feature of visual studio http://blog.codeinside.eu/2014/09/08/Visual-Studio-2013-Paste-Special-JSON-And-Xml/ I generated the classed describing the xml structure, handle it really clean and easy from code and transfomed when required with System.Xml.Serialization https://support.microsoft.com/en-us/kb/815813 in xml doc or whatever was the need.
The same way from xml to c# object https://msdn.microsoft.com/en-us/library/fa420a9y(v=vs.110).aspx.
My personal preference is to not use the xml api directly. Rather, use the model object then serialize and de-serialize it. It's much cleaner in my opinion and the code to do what you actually need is only 3 lines once your have the generic serializer in place.
What you can do is de-serialize your object into an actual "backupatmail" object and then call backupatmail.BackUpItems.Add(your new item here) and then deserialize it back into a string.
This approach is slower than using LinqToXml during runtime but most of the time a extra millisecond or more isn't a big deal.
Here's the serialization/ deserialization code.
using System.Xml;
using System.Xml.Serialization;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
public class SerializationUtils
{
public static T Deserialize<T>(string data)
{
XmlSerializer objSerializer = new XmlSerializer(typeof(T));
using (var reader = new StringReader(data))
{
return (T)objSerializer.Deserialize(reader);
}
}
public static string Serialize<T>(T obj)
{
XmlSerializer objSerializer = new XmlSerializer(typeof(T));
XmlSerializerNamespaces emptyNamespaces = new XmlSerializerNamespaces(new [] { XmlQualifiedName.Empty });
var settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
settings.ConformanceLevel = ConformanceLevel.Auto;
#if DEBUG
settings.Indent = true;
#else
settings.Indent = false;
#endif
using (var stream = new StringWriter())
using (var writer = XmlWriter.Create(stream, settings))
{
objSerializer.Serialize(writer, obj, emptyNamespaces);
return stream.ToString();
}
}
}
and for your use.
string mailItems = GetXmlStringFromSomewhere();
var objMail = SerializationUtils.Deserialize<BackUpMail>(mailItems);
var newItem = new BackUp() { FolderName = "testing1", BackupDate = DateTime.Now};
objMail.BackUpItems.Add(newItem);
var strMailWAddedItem = SerializationUtils.Serialize(objMail);
Here are your entity classes.
public class BackUpMail
{
public List<BackUp> BackUpItems {get;set;}
}
public class BackUp
{
[XmlAttribute("id")]
public string ID {get;set}
[XmlElement("foldername")]
public string FolderName {get;set;}
[XmlElement("backupdate")]
public DateTime BackupDate {get;set;}
[XmlElement("comment")]
public string Comment {get;set}
[XmlElement("numberofparts")]
public string NumberOfParts {get;set}
[XmlElement("lastsucceed")]
public string LastSucceed {get;set}
}
Since you have the code, just parameterize it.
public static void someOtherMethod(){
XmlDocument doc = new XmlDocument();
doc.Load(GlobalSettings.appDefaultFolder + "backups.xml");
// some loop..
doc.DocumentElement.AppendChild(createNode(id[i], foldername[i], backupdate[i]));
doc.Save(GlobalSettings.appDefaultFolder + "backups.xml");
}
public static void createNode(string id, string foldername, string backupdate)
{
XmlElement backupNodeNew = doc.CreateElement("backup");
XmlAttribute backupId = doc.CreateAttribute("id");
backupId.Value = id;
backupNodeNew.Attributes.Append(backupId);
XmlNode nodeTitle = doc.CreateElement("foldername");
nodeTitle.InnerText = foldername;
XmlNode nodeUrl = doc.CreateElement("backupdate");
nodeUrl.InnerText = backupdate;
backupNodeNew.AppendChild(nodeTitle);
backupNodeNew.AppendChild(nodeUrl);
return backupNodeNew;
}
I played a little with Bond using this code:
using System;
using System.IO;
using System.Text;
using System.Xml;
using Bond;
using Bond.Protocols;
using NUnit.Framework;
public class Sandbox
{
[Test]
public void RoundtripWithSchema()
{
var sb = new StringBuilder();
var source = new WithSchema { Value = 1 };
using (XmlWriter xmlWriter = XmlWriter.Create(sb))
{
var writer = new SimpleXmlWriter(xmlWriter);
Serialize.To(writer, source);
}
var xml = sb.ToString();
Console.Write(xml);
Console.WriteLine();
using (var xmlReader = XmlReader.Create(new StringReader(xml)))
{
var reader = new SimpleXmlReader(xmlReader);
var roundtripped = Deserialize<WithSchema>.From(reader); // System.IO.InvalidDataException : Unexpected node type
Assert.AreEqual(source.Value, roundtripped.Value);
}
}
[Test]
public void RoundtripUsingSerializerWithSchema()
{
var sb = new StringBuilder();
var source = new WithSchema { Value = 1 };
using (XmlWriter xmlWriter = XmlWriter.Create(sb))
{
var writer = new SimpleXmlWriter(xmlWriter);
var serializer = new Serializer<SimpleXmlWriter>(typeof(WithSchema));
serializer.Serialize(source, writer);
}
var xml = sb.ToString();
Console.Write(xml);
Console.WriteLine();
using (var xmlReader = XmlReader.Create(new StringReader(xml)))
{
var reader = new SimpleXmlReader(xmlReader);
var serializer = new Deserializer<SimpleXmlReader>(typeof(WithSchema));
var roundtripped = serializer.Deserialize<WithSchema>(reader); // System.IO.InvalidDataException : Unexpected node type
Assert.AreEqual(source.Value, roundtripped.Value);
}
}
}
[Schema]
public class WithSchema
{
[Id(0)]
public int Value { get; set; }
}
Both samples output the expected xml:
<?xml version="1.0" encoding="utf-16"?>
<WithSchema>
<Value>1</Value>
</WithSchema>
Both fail when deserializing throwing System.IO.InvalidDataException : Unexpected node type
Don't know where to look for the bug really, suggestions?
The Bond SimpleXmlReader is having trouble with the <?xml version="1.0" encoding="utf-16"?> line. If you leave this out when serializing, you can deserialize without a problem.
Try something like this
using (XmlWriter xmlWriter = XmlWriter.Create(sb, new XmlWriterSettings { OmitXmlDeclaration = true }))
{
var writer = new SimpleXmlWriter(xmlWriter);
Serialize.To(writer, source);
}
My guess is that XmlNodeType.XmlDeclaration probably needs to be added to the IgnoredTokens set in Bond's SimpleXmlParser.
Bond versions later than v4.0.1 will have this issue (Bond issue #112 on GitHub) fixed.
Inspiration for this answer came from the Bond simple_xml sample.
I need to get clear xml without any namespace and type declarations. Here is the serialized xml:
<placeBetRequest p1:type="PlaceBetRequestTeamed" xmlns:p1="http://www.w3.org/2001/XMLSchema-instance">
...
</placeBetRequest>
Need to someway configure XmlSerializer to set it don't add any attributes but only mine (if I set them with [XmlAttribte]
the clean xml need to looks like this:
<placeBetRequest>
...
</placeBetRequest>
Here is my serialization method:
public static string XmlConvert<T>(T obj, params Type[] wellKnownTypes) where T : class
{
var emptyNamepsaces = new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty });
var settings = new XmlWriterSettings {Indent = true, OmitXmlDeclaration = true};
XmlSerializer serializer = wellKnownTypes == null
? new XmlSerializer(typeof(T))
: new XmlSerializer(typeof(T), wellKnownTypes);
using (var stream = new StringWriter())
using (var writer = XmlWriter.Create(stream, settings))
{
serializer.Serialize(writer, obj, emptyNamepsaces);
return stream.ToString();
}
}
Please help. Thanks.
I've been using regex
string input =
"<p1:placeBetRequest p1:type=\"PlaceBetRequestTeamed\" xmlns:p1=\"http://www.w3.org/2001/XMLSchema-instance\">" +
"</p1:placeBetRequest>";
string pattern = #"(?'prefix'\</?)(?'ns'[^:]*:)";
string output = Regex.Replace(input, pattern, "${prefix}");
I have a library that contains a .NET type. The library has its own configuration (annotations etc) for serializing the type to XML, and I do not have the source code.
No matter what I do, I could not manage to add the prefix I want to add to the root element of the output XML. Using XmlSerializerNamespaces made no difference. Here is a snippet that shows my code at the moment:
var comp = row[0] as LibraryType;
var ser = new XmlSerializer(comp.GetType());
var strWriter = new StringWriter();
var xmlWriter = XmlWriter.Create(strWriter);
ser.Serialize(xmlWriter, comp);
string serXml = strWriter.ToString();
Is there a way in configure XMLSerializer to create an xlm output for root such as
<lt:LibraryType ....
instead of the current
<LibraryType .....
I'm getting ?
Lets say that your library type looks like
public class Foo
{
public int i { get; set; }
}
public class Bar
{
public Foo Foo { get; set; }
}
then serialization should look like
var comp = new Bar {Foo = new Foo()};
var overrides = new XmlAttributeOverrides();
overrides.Add(typeof (Bar), new XmlAttributes {XmlRoot = new XmlRootAttribute {Namespace = "http://tempuri.org"}});
// in case you want to remove prefix from members
var emptyNsAttribute = new XmlAttributes();
emptyNsAttribute.XmlElements.Add(new XmlElementAttribute { Namespace = "" });
overrides.Add(typeof(Bar), "Foo", emptyNsAttribute);
// if you actual library type contains more members, then you have to list all of them
var ser = new XmlSerializer(comp.GetType(), overrides);
var strWriter = new StringWriter();
var xmlWriter = XmlWriter.Create(strWriter);
var ns = new XmlSerializerNamespaces();
ns.Add("lt", "http://tempuri.org");
ser.Serialize(xmlWriter, comp, ns);
string serXml = strWriter.ToString();
and the output will be
<?xml version="1.0" encoding="utf-16"?><lt:Bar xmlns:lt="http://tempuri.org"><Foo><i>0</i></Foo></lt:Bar>