i have been developing a wcf service with rest. Here is my DataContract that i have defined in the service. This is service will be consumed by the android device users and the data will be get passed in the service method in the form of the xml.
[DataContract(Namespace = "")]
public class Employee
{
[DataMember]
public int ID { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public List<City> city { get; set; }
}
[DataContract]
public class City
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string CityName { get; set; }
}
And the following is the servicecontract that i have defined
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "/SaveData/New")]
void SaveData(Employee emp);
}
Now the implementation code for this service is as follows :
public void SaveData(Employee emp)
{
Employee obj = emp;
DataContractSerializer dcs = new DataContractSerializer(typeof(Employee));
using (Stream stream = new FileStream(#"D:\file.xml", FileMode.Create, FileAccess.Write))
{
using (XmlDictionaryWriter writer =
XmlDictionaryWriter.CreateTextWriter(stream, Encoding.UTF8))
{
writer.WriteStartDocument();
dcs.WriteObject(writer, obj);
}
}
When i send the data in xml format using fiddler it is not getting parsed correctly. Here is what i m passing to the method using fiddler :
<Employee>
<ID>1</ID>
<Name>Nitin Singh</Name>
<City>
<Id>1<Id>
<CityName>New Delhi<CityName>
<City>
</Employee>
the output that it is rendering is as follows : -
<?xml version="1.0" encoding="utf-8"?><Employee xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><ID>1</ID><Name>Nitin Singh</Name><city i:nil="true" xmlns:a="http://schemas.datacontract.org/2004/07/SampleService"/></Employee>
I want the city valus should also be present into but it is not happening here. Kindly help me to figure out this. Thanks
XmlSerializer allows you to "flatten" a list into a sequence of identically named elements, like so:
[XmlRoot("Employee", Namespace="")]
public class Employee
{
public int ID { get; set; }
public string Name { get; set; }
[XmlElement("City")]
public List<City> City { get; set; }
}
public class City
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string CityName { get; set; }
}
And, to use it:
public static class XmlSerializationHelper
{
public static string GetXml<T>(T obj, XmlSerializer serializer, bool omitStandardNamespaces)
{
using (var textWriter = new StringWriter())
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true; // For cosmetic purposes.
settings.IndentChars = " "; // For cosmetic purposes.
using (var xmlWriter = XmlWriter.Create(textWriter, settings))
{
if (omitStandardNamespaces)
{
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", ""); // Disable the xmlns:xsi and xmlns:xsd lines.
serializer.Serialize(xmlWriter, obj, ns);
}
else
{
serializer.Serialize(xmlWriter, obj);
}
}
return textWriter.ToString();
}
}
public static string GetXml<T>(this T obj, bool omitNamespace)
{
XmlSerializer serializer = new XmlSerializer(obj.GetType());
return GetXml(obj, serializer, omitNamespace);
}
public static string GetXml<T>(this T obj)
{
return GetXml(obj, false);
}
}
Test code:
var employee = new Employee { Name = "Nitin Singh", ID = 1, City = new[] { new City { CityName = "New Delhi", Id = 1 }, new City { CityName = "Bangalore", Id = 2 } }.ToList() };
var xml = employee.GetXml();
Debug.WriteLine(xml);
For your classes this produces the following XML:
<Employee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ID>1</ID>
<Name>Nitin Singh</Name>
<City>
<Id>1</Id>
<CityName>New Delhi</CityName>
</City>
<City>
<Id>2</Id>
<CityName>Bangalore</CityName>
</City>
</Employee>
Is that what you want? This writes the XML to a string for testing purposes. Instructions for writing to a file are here: How to: Write Object Data to an XML File.
(You made a couple minor mistakes with your data contract -- public List<City> city should have been public List<City> City and public class City needed [DataContract(Namespace = "")]. However, the resulting list would have been two levels deep.)
Related
I need to serialize a class to xml. If a certain condition is met at run-time, I want to add an XML attribute to an element and assign it a value. Sometimes, the "Error" attribute will appear and sometimes it won't.
My code that serializes my objects:
public class XmlToolsRepo : IXmlTools
{
public string SerializeToXML<T>(object obj)
{
string results = null;
Encoding enc = Encoding.UTF8;
using (MemoryStream ms = new MemoryStream())
{
using (XmlTextWriter xw = new XmlTextWriter(ms, enc))
{
xw.Formatting = Formatting.None;
XmlSerializerNamespaces emptyNS = new XmlSerializerNamespaces(new[] { new XmlQualifiedName("", "") });
XmlSerializer xSerializer = new XmlSerializer(typeof(T));
xSerializer.Serialize(xw, obj, emptyNS);
}
results = enc.GetString(ms.ToArray());
}
return results;
}
}
A class with a property that could have a new attribute at run-time:
[DataContract]
public class H204
{
[DataMember]
[XmlAttribute]
public string Code { get; set; }
[DataMember]
public string DW { get; set; }
}
When a condition is met I need for the XML to look like this:
<?xml version="1.0" encoding="UTF-8"?>
<H204 Code="A">
<DW Error="test" />
</H204>
Try following :
public class H204
{
[XmlAttribute(AttributeName = "Code")]
public string Code { get; set; }
[XmlElement(ElementName = "DW")]
public DW dw{ get; set; }
}
public class DW
{
[XmlAttribute(AttributeName = "Error")]
public string text { get; set; }
}
I'm trying to obtain the value of the logicalName attribute of the main node of this xml file:
<?xml version="1.0" encoding="ISO-8859-1"?>
<ticketlayout xmlns="http://www.example.com/ticketlayout" logicalName="target.xml" deviceCode="1" measurement="mm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.com/ticketlayout">
<fontdefinition id="BarCode">
<fontname>Code128bWin</fontname>
<size measure="pt">16</size>
</fontdefinition>
</ticketlayout>
I've tried to add the namespace "xsi", "http://www.w3.org/2001/XMLSchema-instance" this way:
XmlDocument fLayout = new XmlDocument();
fLayout.Load("myFile.xml");
XmlNamespaceManager nsmRequestLayout = new XmlNamespaceManager(fLayout.NameTable);
nsmRequestLayout.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
string sValue = fLayout.SelectNodes("//ticketlayout", nsmRequestLayout)[0].Attributes["name"].Value;
But I get no nodes. I've tried without namespace and no nodes again, and son on.
¿Could please anyone help me?
Thanks in advance.
If you want to get the value : target.xml
Try this code
XmlDocument fLayout = new XmlDocument();
fLayout.Load("myFile.xml"); // your XML file
var attrib = fLayout["ticketlayout"].Attributes["logicalName"].Value;
First of all your XML is not valid.
I modified to look this way in order to achieve what you are looking for.
XML File :
<?xml version="1.0" encoding="UTF-8"?>
<ticketlayout xmlns="http://www.example.com/ticketlayout" logicalName="target.xml" deviceCode="1" measurement="mm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.com/ticketlayout">
<fontdefinition id="BarCode">
<fontname>Code128bWin</fontname>
<size measure="pt">16</size>
</fontdefinition>
</ticketlayout>
I am not sure why you would not have a model structure to deserialize you xml, and then access whatever property/attribute you need.
Example :
Classes:
[XmlRoot(ElementName = "size", Namespace = "http://www.example.com/ticketlayout")]
public class Size
{
[XmlAttribute(AttributeName = "measure")]
public string Measure { get; set; }
[XmlText]
public string Text { get; set; }
}
[XmlRoot(ElementName = "fontdefinition", Namespace = "http://www.example.com/ticketlayout")]
public class Fontdefinition
{
[XmlElement(ElementName = "fontname", Namespace = "http://www.example.com/ticketlayout")]
public string Fontname { get; set; }
[XmlElement(ElementName = "size", Namespace = "http://www.example.com/ticketlayout")]
public Size Size { get; set; }
[XmlAttribute(AttributeName = "id")]
public string Id { get; set; }
}
[XmlRoot(ElementName = "ticketlayout", Namespace = "http://www.example.com/ticketlayout")]
public class Ticketlayout
{
[XmlElement(ElementName = "fontdefinition", Namespace = "http://www.example.com/ticketlayout")]
public Fontdefinition Fontdefinition { get; set; }
[XmlAttribute(AttributeName = "xmlns")]
public string Xmlns { get; set; }
[XmlAttribute(AttributeName = "logicalName")]
public string LogicalName { get; set; }
[XmlAttribute(AttributeName = "deviceCode")]
public string DeviceCode { get; set; }
[XmlAttribute(AttributeName = "measurement")]
public string Measurement { get; set; }
[XmlAttribute(AttributeName = "xsi", Namespace = "http://www.w3.org/2000/xmlns/")]
public string Xsi { get; set; }
[XmlAttribute(AttributeName = "schemaLocation", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
public string SchemaLocation { get; set; }
}
Then you could use a serializer :
public class Serializer
{
public T Deserialize<T>(string input) where T : class
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
using (StringReader stringReader = new StringReader(input))
{
return (T)xmlSerializer.Deserialize(stringReader);
}
}
public string Serialize<T>(T ObjectToSerialize)
{
XmlSerializer xmlSerializer = new XmlSerializer(ObjectToSerialize.GetType());
StringBuilder builder = new StringBuilder();
using (StringWriterWithEncoding textWriter = new StringWriterWithEncoding(builder, Encoding.UTF8))
{
xmlSerializer.Serialize(textWriter, ObjectToSerialize);
return textWriter.ToString();
}
}
}
public class StringWriterWithEncoding : StringWriter
{
Encoding encoding;
public StringWriterWithEncoding(StringBuilder builder, Encoding encoding)
: base(builder)
{
this.encoding = encoding;
}
public override Encoding Encoding
{
get { return encoding; }
}
}
And finally you can access whatever you want by doing the following :
var serializer = new Serializer();
//I used a local file for testing, but it should be the same thing with your file
var xmlInputData = File.ReadAllText(#"MyXmlPath");
var output = serializer.Deserialize<Ticketlayout >(xmlInputData);
var logicalName = output.LogicalName;
This question already has answers here:
Serialize an object to XML
(19 answers)
Closed 5 years ago.
I would like to generate an XML using XMLSerializer. I have an abstract Base class which is being inherited by other classes.
public abstract class Base
{
public string Name {get; set;}
public int ID {get; set;}
public Base(string Name, int ID)
{
this.Name = Name;
this.ID = ID;
}
}
public class HR: Base
{
public HR(string Name, int ID): Base(Name,ID)
{
}
}
public class IT : Base
{
public IT(string Name, int ID): Base(Name,ID)
{
}
}
I am not sure how to generate an XML of format
<Employee>
<HR>
<Name> </Name>
<ID> </ID>
</HR>
<IT>
<Name> </Name>
<ID> </ID>
</IT>
</Employee>
I apologise for the vague question. I have never used XMLSerializer before and not sure how to proceed with it. Any help would be greatly appreciated.
Thanks
As I read your xml, it seems you want to serialize a list of Employee.
I have a solution for you if your list is a member of a class (not directly serializing the list).
public abstract class Employee
{
public string Name { get; set; }
public int ID { get; set; }
public Employee(string Name, int ID)
{
this.Name = Name;
this.ID = ID;
}
}
public class HR : Employee
{
public HR() : base(null, 0) { } // default constructor is needed for serialization/deserialization
public HR(string Name, int ID) : base(Name, ID) { }
}
public class IT : Employee
{
public IT() : base(null, 0) { }
public IT(string Name, int ID) : base(Name, ID) { }
}
public class Group
{
[XmlArray("Employee")]
[XmlArrayItem("HR",typeof(HR))]
[XmlArrayItem("IT",typeof(IT))]
public List<Employee> list { get; set; }
public Group()
{
list = new List<Employee>();
}
}
class Program
{
static void Main(string[] args)
{
Group grp = new Group();
grp.list.Add(new HR("Name HR", 1));
grp.list.Add(new IT("Name IT", 2));
XmlSerializer ser = new XmlSerializer(typeof(Group));
ser.Serialize(Console.Out, grp);
}
}
And the output is :
<?xml version="1.0" encoding="ibm850"?>
<Group xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Employee>
<HR>
<Name>Name HR</Name>
<ID>1</ID>
</HR>
<IT>
<Name>Name IT</Name>
<ID>2</ID>
</IT>
</Employee>
</Group>
Very similar to your desired output, excepted one more element at the root "Group".
Deserialize with the same XmlSerializer(typeof(Group)) should work as well.
I think you need to use the XmlType attributes to make sure your elements show up as <HR> and <IT> instead of <employee xsi:type="HR">. Working demo below:
public abstract class Employee
{
public string Name { get; set; }
public string ID { get; set; }
public Employee(string Name, string ID)
{
this.Name = Name;
this.ID = ID;
}
}
public class HR : Employee
{
public HR(string Name, string ID) : base(Name, ID)
{
}
public HR() : base("No name", "No ID")
{
}
}
public class IT : Employee
{
public IT(string Name, string ID) : base(Name, ID)
{
}
public IT() : base("No name", "No ID")
{
}
}
I added default (parameter-less) constructors for the serializer.
Then you have to have some kind of wrapper object to handle a list of Employees:
public class Employees
{
[XmlElement(typeof(IT))]
[XmlElement(typeof(HR))]
public List<Employee> Employee { get; set; } //It doesn't really matter what this field is named, it takes the class name in the serialization
}
Next, you can use the serializer code from my comment to generate the XML:
var employees = new Employees
{
Employee = new List<Employee>()
{
new IT("Sugan", "88"),
new HR("Niels", "41")
}
};
var serializer = new XmlSerializer(typeof(Employees));
var xml = "";
using (var sw = new StringWriter())
{
using (XmlWriter writer = XmlWriter.Create(sw))
{
serializer.Serialize(writer, employees);
xml = sw.ToString();
}
}
Console.WriteLine(xml);
(Namespaces ommitted for clarity's sake)
This returns the following XML:
<?xml version="1.0" encoding="UTF-8"?>
<Employees xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<IT>
<Name>Sugan</Name>
<ID>88</ID>
</IT>
<HR>
<Name>Niels</Name>
<ID>41</ID>
</HR>
</Employees>
Add the [Serializable] Annotation to the class you want to serialize.
[System.Serializable]
public class Base
{
public string Name { get; set; }
public int ID { get; set; }
public Base(string Name, int ID)
{
this.Name = Name;
this.ID = ID;
}
}
To serialize in XML format, use the following code:
System.Xml.Serialization.XmlSerializer Serializer = new System.Xml.Serialization.XmlSerializer(typeof(Base));
Base Foo = new Base();
string xmldata = "";
using (var stringwriter = new System.IO.StringWriter())
{
using (System.Xml.XmlWriter xmlwriter = System.Xml.XmlWriter.Create(stringwriter))
{
Serializer.Serialize(xmlwriter, Foo);
xml = stringwriter.ToString(); // Your XML
}
}
To deserialize from XML back to your Base object, use the following code:
System.IO.MemoryStream FooStream = new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(xml));
Base Foo;
Foo = (Base)Serializer.Deserialize(FooStream);
I have the following type:
[XmlRoot(Namespace = "http://schemas.datacontract.org/2004/07/MyNamespace")]
public class Location
{
public int Id { get; set; }
public string Name { get; set; }
public Collection<int> DataSourceIds { get; set; }
}
I'm serializing a list of Locations to XML, resulting in the following:
<ArrayOfLocation xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/MyNamespace">
<Location>
<DataSourceIds xmlns:d3p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<d3p1:int>1</d3p1:int>
</DataSourceIds>
<Id>2</Id>
<Name>First</Name>
</Location>
<Location>
<DataSourceIds xmlns:d3p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<d3p1:int>1</d3p1:int>
<d3p1:int>2</d3p1:int>
<d3p1:int>3</d3p1:int>
<d3p1:int>4</d3p1:int>
</DataSourceIds>
<Id>1</Id>
<Name>Second</Name>
</Location>
</ArrayOfLocation>
I then try to deserialize this XML as follows:
var rootAttribute = new XmlRootAttribute("ArrayOfLocation")
{
Namespace = "http://schemas.datacontract.org/2004/07/MyNamespace"
};
var serializer = new XmlSerializer(typeof(Location[]), rootAttribute);
using (var xmlReader = XmlReader.Create(new StreamReader(response.GetResponseStream())))
{
locations = (Location[])serializer.Deserialize(xmlReader);
}
This returns a list of Location objects, with every property set correctly... except DataSourceIds, which remains empty. Why isn't XmlSerializer deserializing the array of integers?
Since it was serialized with DataContractSerializer, you can deserialize it like so:
[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/MyNamespace")]
public class Location
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public Collection<int> DataSourceIds { get; set; }
}
And then use it like:
using (var xmlReader = XmlReader.Create(stream))
{
DataContractSerializer serializer = new DataContractSerializer(typeof(Location[]));
var locations = (Location[])serializer.ReadObject(xmlReader);
Debug.WriteLine(DataContractSerializerHelper.GetXml(locations, serializer)); // Debug check on re-serialization, remove when not needed.
}
The XmlRoot declaration is ignored by DataContractSerializer.
Finally, a utility method for re-serializing to an XML string, for debugging purposes:
public static class DataContractSerializerHelper
{
private static MemoryStream GenerateStreamFromString(string value)
{
return new MemoryStream(Encoding.Unicode.GetBytes(value ?? ""));
}
public static string GetXml<T>(T obj, DataContractSerializer serializer) where T : class
{
using (var textWriter = new StringWriter())
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.IndentChars = " "; // For cosmetic purposes.
using (XmlWriter xmlWriter = XmlWriter.Create(textWriter, settings))
{
serializer.WriteObject(xmlWriter, obj);
}
return textWriter.ToString();
}
}
public static string GetXml<T>(T obj) where T : class
{
DataContractSerializer serializer = new DataContractSerializer(typeof(T));
return GetXml(obj, serializer);
}
}
I have following class. (SIMModel, Product, Item)
public class SIMModel
{
public Product Product { get; set; }
}
public class Product
{
public List<Item> Items { get; set; }
}
public class Item
{
[XmlAttribute("ID")]
public String ID { get; set; }
[XmlAttribute("Name")]
public String Name { get; set; }
public Child_Item Child_Item { get; set; }
public Parent_Item Parent_Item { get; set; }
}
public class Child_Item
{
[XmlAttribute("ID")]
public String ID { get; set; }
}
And I want to make this XML
<SIMModel>
<Product>
<Item ID="N" Name="N-1">
<Child_Item ID="N-1-1">
</Item>
</Proudct>
</SIMModel>
How can i make the Simulation XML using upper class?
I don't know how to wrap each class..
I made a simple Serialize method that serializes to string and removes the namespaces.
private static void Main(string[] args)
{
string result = Serialize(new SIMModel
{
Product = new Product
{
Items = new List<Item>
{
new Item
{
ID = "N",
Name = "N-1",
Child_Item = new Child_Item {ID = "N-1-1"}
}
}
}
});
Console.WriteLine(result);
}
public static string Serialize<T>(T value)
{
if (value == null)
{
return null;
}
//Create our own namespaces for the output
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
//Add an empty namespace and empty value
ns.Add("", "");
XmlSerializer serializer = new XmlSerializer(typeof (T));
XmlWriterSettings settings = new XmlWriterSettings
{
Encoding = new UnicodeEncoding(false, false),
Indent = true,
OmitXmlDeclaration = true
};
using (StringWriter textWriter = new StringWriter())
{
using (XmlWriter xmlWriter = XmlWriter.Create(textWriter, settings))
{
serializer.Serialize(xmlWriter, value, ns);
}
return textWriter.ToString();
}
}
Output:
<SIMModel>
<Product>
<Items>
<Item ID="N" Name="N-1">
<Child_Item ID="N-1-1" />
</Item>
</Items>
</Product>
</SIMModel>