XML Serialization of List<T> - XML Root - c#

First question on Stackoverflow (.Net 2.0):
So I am trying to return an XML of a List with the following:
public XmlDocument GetEntityXml()
{
StringWriter stringWriter = new StringWriter();
XmlDocument xmlDoc = new XmlDocument();
XmlTextWriter xmlWriter = new XmlTextWriter(stringWriter);
XmlSerializer serializer = new XmlSerializer(typeof(List<T>));
List<T> parameters = GetAll();
serializer.Serialize(xmlWriter, parameters);
string xmlResult = stringWriter.ToString();
xmlDoc.LoadXml(xmlResult);
return xmlDoc;
}
Now this will be used for multiple Entities I have already defined.
Say I would like to get an XML of List<Cat>
The XML would be something like:
<ArrayOfCat>
<Cat>
<Name>Tom</Name>
<Age>2</Age>
</Cat>
<Cat>
<Name>Bob</Name>
<Age>3</Age>
</Cat>
</ArrayOfCat>
Is there a way for me to get the same Root all the time when getting these Entities?
Example:
<Entity>
<Cat>
<Name>Tom</Name>
<Age>2</Age>
</Cat>
<Cat>
<Name>Bob</Name>
<Age>3</Age>
</Cat>
</Entity>
Also note that I do not intend to Deserialize the XML back to List<Cat>

There is a much easy way:
public XmlDocument GetEntityXml<T>()
{
XmlDocument xmlDoc = new XmlDocument();
XPathNavigator nav = xmlDoc.CreateNavigator();
using (XmlWriter writer = nav.AppendChild())
{
XmlSerializer ser = new XmlSerializer(typeof(List<T>), new XmlRootAttribute("TheRootElementName"));
ser.Serialize(writer, parameters);
}
return xmlDoc;
}

If I understand correctly, you want the root of the document to always be the same, whatever the type of element in the collection ? In that case you can use XmlAttributeOverrides :
XmlAttributeOverrides overrides = new XmlAttributeOverrides();
XmlAttributes attr = new XmlAttributes();
attr.XmlRoot = new XmlRootAttribute("TheRootElementName");
overrides.Add(typeof(List<T>), attr);
XmlSerializer serializer = new XmlSerializer(typeof(List<T>), overrides);
List<T> parameters = GetAll();
serializer.Serialize(xmlWriter, parameters);

A better way to the same thing:
public XmlDocument GetEntityXml<T>()
{
XmlAttributeOverrides overrides = new XmlAttributeOverrides();
XmlAttributes attr = new XmlAttributes();
attr.XmlRoot = new XmlRootAttribute("TheRootElementName");
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);
List<T> parameters = GetAll<T>();
ser.Serialize(writer, parameters);
}
return xmlDoc;
}

so simple....
public static XElement ToXML<T>(this IList<T> lstToConvert, Func<T, bool> filter, string rootName)
{
var lstConvert = (filter == null) ? lstToConvert : lstToConvert.Where(filter);
return new XElement(rootName,
(from node in lstConvert
select new XElement(typeof(T).ToString(),
from subnode in node.GetType().GetProperties()
select new XElement(subnode.Name, subnode.GetValue(node, null)))));
}

Related

C# serializer not adding prefix to root element

Seen lots of people with this same issue and no answers anywhere, so answering it myself here;
When serializing an XML class that should have a prefix attached to it, the prefix is missing.
[XmlRoot(ElementName = "Preadvice", Namespace = "http://www.wibble.com/PreadviceRequest")]
public class Preadvice
{
}
var XMLNameSpaces = new XmlSerializerNamespaces();
XMLNameSpaces.Add("isd", "http://www.wibble.com/PreadviceRequest");
And this is my serializing method;
public static string SerializeStandardObject<T>(T obj, XmlSerializerNamespaces ns, XmlAttributeOverrides xao, XmlRootAttribute xra)
{
XmlSerializer serializer = new XmlSerializer(typeof(T), (xao == null ? new XmlAttributeOverrides() : xao), new Type[] { obj.GetType() }, (xra == null ? new XmlRootAttribute(obj.GetType().Name) : xra), "");
using (StringWriter sw = new StringWriter())
{
using (System.Xml.XmlTextWriter writer = new System.Xml.XmlTextWriter(sw))
{
serializer.Serialize(writer, obj, (ns == null ? new XmlSerializerNamespaces() : ns));
}
return sw.ToString();
}
}
This produces;
<?xml version="1.0" encoding="utf-16"?>
<Preadvice xmlns:isd="http://www.wibble.com/PreadviceRequest">
</Preadvice>
Which is missing the prefix, it should look like this..
<?xml version="1.0" encoding="utf-16"?>
<isd:Preadvice xmlns:isd="http://www.wibble.com/PreadviceRequest">
</isd:Preadvice>
If your serializer includes an xmlrootattribute when it is created, it doesn't apply namespaces you have specified manually, and therefore misses the "isd" tag off the first element. The easiest fix is to remove the xmlrootattribute;
public static string SerializeStandardObject<T>(T obj, XmlSerializerNamespaces ns)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
using (StringWriter sw = new StringWriter())
{
using (System.Xml.XmlTextWriter writer = new System.Xml.XmlTextWriter(sw))
{
serializer.Serialize(writer, obj, (ns == null ? new XmlSerializerNamespaces() : ns));
}
return sw.ToString();
}
}

XML Serialization Missing Some Elements

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));

read xml document and update all fields c#

i'm trying to read xml file and update all it's value my xml was
<adf>
<prospect>
<requestdate>2015-10-29 07-38-22</requestdate>
<id sequence="1" source="admin.ss.com">admin.ss.com</id>
<vehicle interest="buy" status="">
<id sequence="1" source=""></id>
<year></year>
<make></make>
<model>camry</model>
<vin></vin>
<stock></stock>
<trim></trim>
</vehicle>
<customer>
<contact primarycontact="1">
<name part="first">Jessica</name>
<name part="last">Sonntag</name>
<email>js#test.com</email>
<phone type="phone" time="day">555-585-5555</phone>
<address>
<street line="1"></street>
<city></city>
<regioncode></regioncode>
<postalcode></postalcode>
<country></country>
</address>
</contact>
<comments>Vehicle Year: 2011 Comments: </comments>
</customer>
<provider>
<name part="full">ST</name>
<service> Engine Marketing</service>
<phone>1-866-572-3952</phone>
</provider>
</prospect>
</adf>
so i select node like below
var items = (from item in xmlDoc.Descendants("requestdate")
select item).ToList();
then i can update only requestdata tag value so do i have to repeat same for all tags or is there any good way to accomplish this.
Regards
There is an easy way to do this. This one is a hidden gem. Most people may not know this. This feature came in VS2013 and it's called "Paste XML as Classes."
Save your xml (Ex: MyXml.XML)
Create a new Console project
Open the Xml in Visual studio
Copy All contents of the xml (Ctl+A, Ctl + C)
Add a new class to your project. You can give any name you like.
Go to Edit>Paste Special>Paste XML as classes.
Add another class to your project. Then add below two methods to that class.
public static string Serialise<T>(T serialisableObject)
{
var doc = new XmlDocument();
using (var stream = new StringWriter())
{
var settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
XmlWriter xmlWriter = XmlWriter.Create(stream, settings);
var ns = new XmlSerializerNamespaces();
ns.Add("", "");
var xmlSerializer = new XmlSerializer(typeof(T));
xmlSerializer.Serialize(xmlWriter, serialisableObject, ns);
doc.LoadXml(stream.ToString());
}
return doc.InnerXml;
}
public static T Deserialise<T>(string xml)
{
T list;
using (var reader = new StringReader(xml))
{
var serialiser = new XmlSerializer(typeof(T));
list = (T)serialiser.Deserialize(reader);
}
return list;
}
Then in your console applications Main method; add this.
var myObj = new adf();
myObj.prospect = new adfProspect();
myObj.prospect.customer = new adfProspectCustomer(){comments = "dgsrtetetete"};
//populate all fields.....
var xml = MySerializer.Serialise(myObj);
File.WriteAllText(#"C:\myNewXml.xml", xml);
That's it. Same way now you can deserialise an xml object in to your class.
Try the XmlSerializer class: https://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer(v=vs.110).aspx If you serialize/deserialize the xml then up dating is trivial.
If you wanted to change every phone number to "0123456789" you could do something like:
var xDoc = XDocument.Load("document.xml");
var results = from phone in xDoc.Descendants("phone") select phone;
foreach (XElement result in results)
{
element.SetValue("0123456789");
}
i have came up with solution with support two extension method i'm iterating all nodes and update.(since my xml is not too big or complicated this one would be a good solution)
with help of these two extension methods
public static void IterateThroughAllNodes(this XmlDocument doc, Action<XmlNode> elementVisitor)
{
if (doc != null && elementVisitor != null)
{
foreach (XmlNode node in doc.ChildNodes)
{
DoIterateNode(node, elementVisitor);
}
}
}
public static void IterateThrough(this XmlNodeList nodes, Action<XmlNode> elementVisitor)
{
if (nodes != null && elementVisitor != null)
{
foreach (XmlNode node in nodes)
{
DoIterateNode(node, elementVisitor);
}
}
}
private static void DoIterateNode(XmlNode node, Action<XmlNode> elementVisitor)
{
elementVisitor(node);
foreach (XmlNode childNode in node.ChildNodes)
{
DoIterateNode(childNode, elementVisitor);
}
}
then i can update my xml nodes as below
XmlDocument doc = new XmlDocument();
doc.Load(Server.MapPath("~/xmlmail.xml"));
var email = new XmlEmail();
doc.IterateThroughAllNodes(
delegate(XmlNode node)
{
if (node.Name.Equals("requestdate"))
node.InnerText= email.RequestDate.ToLongDateString();
if (node.Name.Equals("vehicle"))
{
XmlNodeList childs = node.ChildNodes;
childs.IterateThrough(delegate(XmlNode vnode)
{
if (vnode.Name.Equals("id"))
vnode.InnerText= email.VehicleId.ToString();
if (vnode.Name.Equals("year"))
vnode.InnerText= email.Year.ToString();
if (vnode.Name.Equals("make"))
vnode.InnerText= email.Make;
if (vnode.Name.Equals("model"))
vnode.InnerText= email.Model;
if (vnode.Name.Equals("vin"))
vnode.InnerText= email.Vin;
if (vnode.Name.Equals("trim"))
vnode.InnerText = email.Trim;
});
}
if (node.Name.Equals("customer"))
{
XmlNodeList childs = node.ChildNodes;
childs.IterateThrough(delegate(XmlNode vnode)
{
if (vnode.Attributes != null && (vnode.Name.Equals("name") && vnode.Attributes["part"].Value.Equals("first")))
vnode.InnerText= email.FirstName;
if (vnode.Attributes != null && (vnode.Name.Equals("name") && vnode.Attributes["part"].Value.Equals("last")))
vnode.InnerText= email.LastName;
if (vnode.Name.Equals("email"))
vnode.InnerText= email.Email;
if (vnode.Name.Equals("phone"))
vnode.InnerText= email.Phone;
if (vnode.Name.Equals("comments"))
vnode.InnerText= email.Comments;
if (vnode.Name.Equals("address"))
{
XmlNodeList addresschilds = vnode.ChildNodes;
addresschilds.IterateThrough(delegate(XmlNode anode)
{
if (anode.Name.Equals("street"))
anode.InnerText= email.Street;
if (anode.Name.Equals("city"))
anode.InnerText= email.City;
if (anode.Name.Equals("phone"))
anode.InnerText= email.Phone;
if (anode.Name.Equals("regioncode"))
anode.InnerText= email.RegionCode;
if (anode.Name.Equals("postalcode"))
anode.InnerText= email.Postalode;
if (anode.Name.Equals("country"))
anode.InnerText= email.Country;
});
}
});
}
});

How to serialize List<T> to XML Document.?

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);

XML remove nil attribute

I am doing some XmlOverrides and setting properties to nullable (F1 in this case). I would want to delete nil="true" and the namespace around this attribute, but I can't remove it with any method I've tried.
Nested n = new Nested();
n.Nest = "2";
n.F1 = null;
XmlAttributeOverrides overrides = new XmlAttributeOverrides();
XmlAttributes att = new XmlAttributes();
XmlElementAttribute el = new XmlElementAttribute("F1");
el.IsNullable = true;
att.XmlElements.Add(el);
overrides.Add(typeof(Nested), "F1", att);
XmlSerializer xs = new XmlSerializer(typeof(Nested), overrides);
var faultDocument = new XmlDocument();
var nav = faultDocument.CreateNavigator();
var ns = new XmlSerializerNamespaces();
ns.Add("", "");
using (var writer = nav.AppendChild())
{
xs.Serialize(writer, n, ns);
}
XML I get is like this:
<Nested>
<F1 p2:nil="true" xmlns:p2="http://www.w3.org/2001/XMLSchema-instance"/>
<Nest>2</Nest>
</Nested>
But I would want that F1 element be empty, without nil and xmlns
<Nested>
<F1/>
<Nest>2</Nest>
</Nested>
Try to add in Nested class [XmlElement(ElementName = "F1", IsNullable = true)] in property F1.
I managed to solve it, not sure if it's the best way to do it:
private static void RemoveNils(XElement elem)
{
string nilNamespace = "{http://www.w3.org/2001/XMLSchema-instance}nil";
//first condition should be enough, the rest are just fail-safes
if (elem.Attributes().Any(name => name.Name == nilNamespace) && elem.Elements().Count() == 0 && elem.IsEmpty)
{
elem.Attributes().Remove();
return;
}
foreach (XElement el in elem.Elements())
RemoveNils(el);
}
Try this
Nested n = new Nested();
n.Nest = "2";
n.F1 = null;
XmlAttributeOverrides overrides = new XmlAttributeOverrides();
XmlAttributes att = new XmlAttributes();
XmlElementAttribute el = new XmlElementAttribute("F1");
el.IsNullable = true;
att.XmlElements.Add(el);
overrides.Add(typeof(Nested), "F1", att);
XmlSerializer xs = new XmlSerializer(typeof(Nested));
var faultDocument = new XmlDocument();
var nav = faultDocument.CreateNavigator();
StringWriter strWriter = new StringWriter();
XmlTextWriter TextWriter = new XmlTextWriter(strWriter);
var ns = new XmlSerializerNamespaces();
ns.Add("", "");
xs.Serialize(TextWriter, n, ns);
ReqXml = strWriter.ToString();
TextWriter.Close();
return ReqXml;

Categories