I'm serialising class to specific XML format. Below is the class structure & code I've used to serialize it. Serailized file tend to miss element name "Address".
I've 3 classes StudentInfo which has two properties of type "Student" & "Address"
[Serializable]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlRoot("StudentInfo", Namespace = "http://TestBizTalkMap.Student")]
public class StudentInfo
{
[System.Xml.Serialization.XmlElement("", Namespace = "")]
public Student Student { get; set; }
[System.Xml.Serialization.XmlElement("ns1", Namespace = "ns1:http://TestBizTalkMap.Address")]
public Address Address { get; set; }
}
[Serializable]
public class Student
{
public string EnrollNo { get; set; }
public string Name { get; set; }
public string BTSReceivedOn { get; set; }
}
[Serializable]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlRoot("Address", Namespace = "http://TestBizTalkMap.Address")]
public class Address
{
[XmlElement("",Namespace="")]
public string City { get; set; }
[XmlElement("", Namespace = "")]
public string State { get; set; }
}
Code Used to serialze it:
public XmlDocument GetXMLSchema<T>(T type, string schemeNameSpace)
{
XmlDocument xmlDoc = new XmlDocument();
XmlSerializer xmlSerializer = new XmlSerializer(type.GetType());
try
{
using (MemoryStream xmlStream = new MemoryStream())
{
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("ns0", schemeNameSpace);
xmlSerializer.Serialize(xmlStream, type, ns);
xmlStream.Position = 0;
xmlDoc.Load(xmlStream);
if (xmlDoc.FirstChild.NodeType == XmlNodeType.XmlDeclaration)
{
xmlDoc.RemoveChild(xmlDoc.FirstChild);
}
}
}
catch (Exception ex)
{
throw ex;
}
return xmlDoc;
}
it serializes it to as
<ns0:StudentInfo xmlns:ns0="http://TestBizTalkMap.Student">
<Student>
<EnrollNo>EnrollNl</EnrollNo>
<Name>Name</Name>
<BTSReceivedOn>BTSReceivedOn</BTSReceivedOn>
</Student>
<ns1 xmlns="http://TestBizTalkMap.Address">
<City>City</City>
<State>State</State>
</ns1>
</ns0:StudentInfo
Whereas I want it to get serialised as
<ns0:StudentInfo xmlns:ns0="http://TestBizTalkMap.Student">
<Student>
<EnrollNo>EnrollNo_0</EnrollNo>
<Name>Name_0</Name>
<BTSReceivedOn>BTSReceivedOn_0</BTSReceivedOn>
</Student>
<ns1:Adress xmlns:ns1="http://TestBizTalkMap.Address">
<City>City_0</City>
<State>State_0</State>
</ns1:Adress>
</ns0:StudentInfo>
Any help?
Thanks
You seem to have got awfully confused between names and namespaces. The name of your Address element is Address, not ns1, and its namespace is http://TestBizTalkMap.Address, not ns1:http://TestBizTalkMap.Address.
This is all you need to generate the correct XML.
[XmlRoot(Namespace = "http://TestBizTalkMap.Student")]
public class StudentInfo
{
[XmlElement(Namespace = "")]
public Student Student { get; set; }
[XmlElement(Namespace = "http://TestBizTalkMap.Address")]
public Address Address { get; set; }
}
public class Student
{
public string EnrollNo { get; set; }
public string Name { get; set; }
public string BTSReceivedOn { get; set; }
}
public class Address
{
[XmlElement(Namespace = "")]
public string City { get; set; }
[XmlElement(Namespace = "")]
public string State { get; set; }
}
The namespace prefixes are unimportant, but if you really want them to be ns0 and ns1 then you can specify these via the XmlSerializerNamespaces you pass to the Serialize method:
var ns= new XmlSerializerNamespaces();
ns.Add("ns0", "http://TestBizTalkMap.Student");
ns.Add("ns1", "http://TestBizTalkMap.Address");
And if you don't want the XML Declaration, then don't load the resulting XML into an XmlDocument and remove it, just stop it being written in the first place using XmlWriterSettings:
var settings = new XmlWriterSettings
{
OmitXmlDeclaration = true,
// ...
};
See this fiddle for a working demo.
Related
I have the following XML class structure:
[XmlRoot(ElementName = "Envelope", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public class Envelope
{
[XmlElement(ElementName = "Body", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public Body Body { get; set; }
}
[XmlRoot(ElementName = "Body")]
public class Body
{
[XmlElement(ElementName = "CustomerBundleMaintainConfirmation_sync_V1", Namespace = "http://sap.com/xi/SAPGlobal20/Global")]
public CustomerMaintainConfirmation CustomerMaintainConfirmation { get; set; }
}
[XmlRoot(ElementName = "CustomerBundleMaintainConfirmation_sync_V1")]
public class CustomerMaintainConfirmation
{
[XmlElement(ElementName = "Log")]
public Log Log { get; set; }
}
[XmlRoot(ElementName = "Log")]
public class Log
{
[XmlElement(ElementName = "MaximumLogItemSeverityCode")]
public string MaximumLogItemSeverityCode { get; set; }
[XmlElement(ElementName = "Item")]
public Item Item { get; set; }
}
[XmlRoot(ElementName = "Item")]
public class Item
{
[XmlElement(ElementName = "TypeID")]
public string TypeID { get; set; }
[XmlElement(ElementName = "CategoryCode")]
public string CategoryCode { get; set; }
[XmlElement(ElementName = "SeverityCode")]
public string SeverityCode { get; set; }
[XmlElement(ElementName = "Note")]
public string Note { get; set; }
}
And this is the XML I am working with:
<?xml version="1.0" encoding="UTF-8"?>
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:Header />
<soap-env:Body>
<n0:CustomerBundleMaintainConfirmation_sync_V1 xmlns:n0="http://sap.com/xi/SAPGlobal20/Global" xmlns:prx="urn:sap.com:proxy:LBK:/1SAI/TAE6F3228CC6D723FF1823E:804">
<Log>
<MaximumLogItemSeverityCode>3</MaximumLogItemSeverityCode>
<Item>
<TypeID>018</TypeID>
<CategoryCode>YES</CategoryCode>
<SeverityCode>0</SeverityCode>
<Note>TestNotes</Note>
</Item>
</Log>
</n0:CustomerBundleMaintainConfirmation_sync_V1>
</soap-env:Body>
</soap-env:Envelope>
When I attempt to deserialize this data into my classes, for whatever reason the "Log" class is null. Envelope, Body and CustomerMaintainConfirmation are all populated correctly. I see no reason why this is the case, but I've been staring at this for so long as this point I'm absolutely sure I am missing a mistake in and amongst my code somewhere.
This last piece of code is inside of the method that does the actual deserializing:
XmlSerializer serializer = new XmlSerializer(typeof(Envelope));
using (StreamReader responseReader = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
{
return (Envelope)serializer.Deserialize(responseReader);
}
I'm still working through it, but if anyone could point out any issues they might see with what I've provided, please let me know.
It's a namespace inconsistency. It deserializes with this change:
[XmlRoot(ElementName = "CustomerBundleMaintainConfirmation_sync_V1")]
public class CustomerMaintainConfirmation
{
[XmlElement(ElementName = "Log", Namespace = "")]
public Log Log { get; set; }
}
You just miss the empty namespace indication on your element:
[XmlRoot(ElementName = "CustomerBundleMaintainConfirmation_sync_V1")]
public class CustomerMaintainConfirmation
{
[XmlElement(ElementName = "Log", Namespace = "")]
public Log Log { get; set; }
}
This is required, as apparently, your Log element has the empty namespace even though the CustomerBundleMaintainConfirmation_sync_V1 above has a nonempty one.
That's the only change in your code to make it work as shown in a fiddle.
I'm doing a C# project and I have an object encoded in XML; an example instance would be:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Entity Type="StartRunTestSetResponse">
<Fields>
<Field Name="SuccessStaus">
<Value>2</Value>
</Field>
<Field Name="info">
<Value></Value>
</Field>
</Fields>
</Entity>
I need the attribute information because it is a necessity in the Key-Value pairs' the object has.
My deserialization grammar looks like this:
[DataContract(Name="Entity", Namespace="")]
[XmlSerializerFormat]
[KnownType(typeof(SRTSRField))]
[KnownType(typeof(SRTSRValue))]
public class StartRunTestSetResponse
{
[DataMember(Name="Type"), XmlAttribute("Type")]
public string type { get; set; }
[DataMember(Name = "Fields", IsRequired = true), XmlElement("Fields")]
public List<SRTSRField> fields { get; set; }
internal StartRunTestSetResponse() { fields = new List<SRTSRField>(); }
}
[DataContract(Name = "Field", Namespace = "")]
[KnownType(typeof(SRTSRValue))]
public class SRTSRField
{
[DataMember(Name = "Name"), XmlAttribute("Name")]
public string name {get; set;}
[DataMember(Name = "Value"), XmlElement("Value")]
public SRTSRValue value { get; set; }
}
[DataContract(Name = "Value", Namespace = "")]
public class SRTSRValue
{
[DataMember, XmlText]
public string value { get; set; }
}
Now, it doesn't work; at the moment it parses down to the Fields element and then any child of it is null.
You can simplify your model
public class Entity
{
[XmlAttribute]
public string Type { get; set; }
[XmlArrayItem("Field")]
public Field[] Fields { get; set; }
}
public class Field
{
[XmlAttribute]
public string Name { get; set; }
public string Value { get; set; }
}
So deserialization would be
XmlSerializer ser = new XmlSerializer(typeof(Entity));
using (StringReader sr = new StringReader(xmlstring))
{
var entity = (Entity)ser.Deserialize(sr);
}
[XmlRoot(ElementName="Field")]
public class Field {
[XmlElement(ElementName="Value")]
public string Value { get; set; }
[XmlAttribute(AttributeName="Name")]
public string Name { get; set; }
}
[XmlRoot(ElementName="Fields")]
public class Fields {
[XmlElement(ElementName="Field")]
public List<Field> Field { get; set; }
}
[XmlRoot(ElementName="Entity")]
public class Entity {
[XmlElement(ElementName="Fields")]
public Fields Fields { get; set; }
[XmlAttribute(AttributeName="Type")]
public string Type { get; set; }
}
Createdy by: http://xmltocsharp.azurewebsites.net/
It's really useful
I would create a dictionary using xml linq.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication74
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
Dictionary<string,int?> dict1 = doc.Descendants("Field")
.GroupBy(x => (string)x.Attribute("Name"), y => string.IsNullOrEmpty((string)y.Element("Value")) ? null : (int?)y.Element("Value"))
.ToDictionary(x => x.Key, y => y.FirstOrDefault());
}
}
}
I'm trying to deserialize an XML file with XmlSerializer. However i am getting this exception: There is an error in XML document (1, 41).InnerException Message "ReplicationStatus xmlns='DistributionServices' was not expected."
The XML file looks like this:
<?xml version="1.0" encoding="UTF-8" ?>
<ts:Status xmlns:ts="DistributionServices">
<Server>DUMMY</Server>
<Object>DUMMY</Object>
<Port>123</Port>
<Code>DUMMY</Code>
<Key>b0ed5e56</Key>
</ts:Status>
The code that I have used is as follows:
MessageData data = new MessageData();
XmlSerializer xmlSerializer = new XmlSerializer(data.GetType());
data = (MessageData)xmlSerializer.Deserialize(new StringReader(msgData));
Here, msgData is the string containing the xml shown above.
MessageData class looks like this:
[Serializable,XmlType("Status")]
public class MessageData
{
[XmlElement("Server")]
public string Server { get; set; }
[XmlElement("Object")]
public string Object { get; set; }
[XmlElement("Port")]
public string Port { get; set; }
[XmlElement("Code")]
public string Code { get; set; }
[XmlElement("Key")]
public string Key { get; set; }
}
Please let me know what I am doing wrong.
You have to declare the namespace in your class and set it to empty on your properties. Change your class model to this and it should work fine.
[Serializable, XmlRoot("Status", Namespace = "DistributionServices")]
public class MessageData
{
[XmlElement(Namespace = "")]
public string Server { get; set; }
[XmlElement(Namespace = "")]
public string Object { get; set; }
[XmlElement(Namespace = "")]
public string Port { get; set; }
[XmlElement(Namespace = "")]
public string Code { get; set; }
[XmlElement(Namespace = "")]
public string Key { get; set; }
}
BTW: you don't have to name XmlElement's explicit if they have the same name as the property.
I'm deserializing data received from a web-service.
The problem is that the deserialization of List returns an empty list and no exception are generated. Can you help me figure out why?
We have tried several possible syntax. The code below is the closest to the correct solution but we cannot deserialize correctly as a list of classes.
<ArrayOfBatch xmlns="http://schemas.datacontract.org/2004/07/myns" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<MaasBatch>
<BatchName>All Users</BatchName>
<Users>
<MaasUsers>
<firstName>bob</firstName>
<lastName>thetest</lastName>
<sourceEmail>bob#source.com</sourceEmail>
<sourceTenantID>111</sourceTenantID>
<targetEmail>bob#target.com</targetEmail>
<targetTenantID>222</targetTenantID>
</MaasUsers>
</Users>
</MaasBatch>
</ArrayOfBatch>
Code:
List<MAASBatch> lstMaasBatches = null;
try
{
string target = string.Empty;
using (var response = request.GetResponse())
{
Stream streamReader = response.GetResponseStream();
DataContractSerializer serializer = new DataContractSerializer(typeof(List<MAASBatch>));
lstMaasBatches = (List<MAASBatch>)serializer.ReadObject(streamReader);
streamReader.Close();
}
return lstMaasBatches;
}
catch (Exception exc)
{
return lstMaasBatches;
}
Class:
[DataContract(Name = "MAASBatch", Namespace = "http://schemas.datacontract.org/2004/07/myns")]
[KnownType(typeof(MAASUsers))]
public class MAASBatch
{
[DataMember]
public string BatchName { get; set; }
[DataMember]
public List<MAASUsers> Users { get; set; }
[OnDeserializing]
internal void OnDeserializingCallBack(StreamingContext streamingContext)
{
this.Users = new List<MAASUsers>();
}
}
[DataContract(Name = "MAASUsers", Namespace = "http://schemas.datacontract.org/2004/07/myns")]
public class MAASUsers
{
[DataMember]
public string firstName { get; set; }
[DataMember]
public string lastName { get; set; }
[DataMember]
public string sourceEmail { get; set; }
[DataMember]
public int sourceAgentID { get; set; }
[DataMember]
public string targetEmail { get; set; }
[DataMember]
public int targetAgentID { get; set; }
}
Try to add Order and Name attribute to the Contract class.
Sample:
[DataMember(Order = 1, Name = "firstName")]
The data contract element name is "MAASUsers" but in the xml the element is named "MaasUsers". The data contract serializer is case sensitive so it will NOT match these two up.
i am having an XML string like
<?xml version="1.0"?>
<FullServiceAddressCorrectionDelivery xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<AuthenticationInfo xmlns="http://www.usps.com/postalone/services/UserAuthenticationSchema">
<UserId xmlns="">FAPushService</UserId>
<UserPassword xmlns="">Password4Now</UserPassword>
</AuthenticationInfo>
</FullServiceAddressCorrectionDelivery>
In Order to map the nodes with Class, i am having the class structure like
[Serializable]
public class FullServiceAddressCorrectionDelivery
{
[XmlElement("AuthenticationInfo")]
public AuthenticationInfo AuthenticationInfo
{
get;
set;
}
}
[Serializable]
public class AuthenticationInfo
{
[XmlElement("UserId")]
public string UserId
{
get;
set;
}
[XmlElement("UserPassword")]
public string UserPassword
{
get;
set;
}
}
For De-serialization , i used xmlserializer to De-serialize the object
byte[] byteArray = System.Text.Encoding.ASCII.GetBytes(xmlString);
MemoryStream stream = new MemoryStream(byteArray);
XmlSerializer xs = new XmlSerializer(typeof(FullServiceAddressCorrectionDelivery));
var result = (FullServiceAddressCorrectionDelivery)xs.Deserialize(stream);
but the value FullServiceAddressCorrectionDelivery object is always null..
please help me what i am doing wrong here....
Add namesapce on the XmlElement attribute as described here
[Serializable]
public class FullServiceAddressCorrectionDelivery
{
[XmlElement("AuthenticationInfo",
Namespace =
"http://www.usps.com/postalone/services/UserAuthenticationSchema")]
public AuthenticationInfo AuthenticationInfo
{
get;
set;
}
}
[Serializable]
public class AuthenticationInfo
{
[XmlElement("UserId", Namespace="")]
public string UserId
{
get;
set;
}
[XmlElement("UserPassword", Namespace = "")]
public string UserPassword
{
get;
set;
}
}