I have a simple class with two properties:
[XmlRoot("response")]
public class Response
{
[XmlAttribute("code")]
string Code { get; set; }
[XmlAttribute("message")]
string Message { get; set; }
}
I try to deserialize an XML string with XmlSerializer:
static void Main(string[] args)
{
string xml = "<response code=\"a\" message=\"b\" />";
using(var ms = new MemoryStream())
using(var sw = new StreamWriter(ms))
{
sw.Write(xml);
sw.Flush();
ms.Position = 0;
XmlSerializer ser = new XmlSerializer(typeof(Response));
ser.UnknownAttribute += new XmlAttributeEventHandler(ser_UnknownAttribute);
var obj = ser.Deserialize(ms);
}
}
static void ser_UnknownAttribute(object sender, XmlAttributeEventArgs e)
{
throw new NotImplementedException();
}
The UnknownAttribute event gets fired at the code attribute, it does not get deserialized.
What is the reason for this? Am I using the XmlAttributeAttribute wrong?
This is because the attributes are not public in your class:
[XmlRoot("response")]
public class Response
{
[XmlAttribute("code")]
public string Code { get; set; }
[XmlAttribute("message")]
public string Message { get; set; }
}
From the documentation of XmlAttributeAttribute (emphasis is mine):
You can assign the XmlAttributeAttribute only to public fields or public properties that return a value (or array of values) that can be mapped to one of the XML Schema definition language (XSD) simple types (including all built-in datatypes derived from the XSD anySimpleType type).
Related
I don't know if the topic is correct, if not please correct. So far i am not sure what to search for my problem so maybe the question has already been answered before.
Currently i have the following class (as example):
[Serializable]
public class Sample
{
public string Something { get; set; }
public List<Parameter> Parameters { get; set; }
}
[Serializable]
public class Parameter
{
public string Name { get; set; }
public string Value { get; set; }
}
This structure i have to serialize to the following XML:
<Sample>
<Something>1234512345112345</Something>
<Parameters>
<Name>Value</Name>
<Name>Value</Name>
</Parameters>
</Sample>
So the XML should contain the property value of the attribute "Name" as XML-Element Name.
Update 20.05.2015
I have the following XML content:
<?xml version="1.0" encoding="utf-16" ?>
<ProcessData>
<ID>123456</ID>
<IDYTPE>BASEPLATE</IDYTPE>
<State>FAIL</State>
<Recipe>654321</Recipe>
<ProcessDataParameter>
<test_0>0</test_0>
<test_1>12,34</test_1>
<test_2>24,68</test_2>
<test_3>37,02</test_3>
<test_4>49,36</test_4>
<test_5>61,7</test_5>
</ProcessDataParameter>
</ProcessData>
When i try to use the following code to deserialize:
public void ReadXml(XmlReader reader)
{
reader.ReadStartElement("ProcessData");
this.Id = reader.ReadElementString("ID");
this.IdType = reader.ReadElementString("IDYTPE");
this.State = reader.ReadElementString("State");
this.Recipe = reader.ReadElementString("Recipe");
reader.ReadStartElement("ProcessDataParameter");
this.ProcessDataParameter = new List<ProcessDataParameter>();
var subTree = reader.ReadSubtree();
while (subTree.Read())
{
if (subTree.NodeType == XmlNodeType.Text)
{
var nm = subTree.LocalName;
//Parameters.Add(new Parameter { Name = nm, Value = subTree.Value });
}
}
reader.ReadEndElement();
}
Everything gets read out fine expect the process data parameters.
It seems like the subTree.Read() just reades the element out of the XML content instead of all elements contained in the .
In the while loop the reader goes through the following values (debuged)
test_0 (start tag)
0 (value between the tag)
test_0 (end tag
and then out of the while.
Seems like the reader sees the as an subtree.
Further only the 0 - value gets recognized as XmlNodeType.Text
You could implement IXmlSerializable and create your own custom serialization behaviour for your Sample class. So in your case something like this should work
[Serializable]
public class Sample : IXmlSerializable
{
public string Something { get; set; }
public List<Parameter> Parameters { get; set; }
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
XmlDocument doc = new XmlDocument();
doc.Load(reader);
Something = doc.SelectSingleNode(#"/Sample/Something").FirstChild.Value;
var parameters = doc.SelectSingleNode(#"/Sample/Parameters");
if (parameters.HasChildNodes)
{
Parameters = new List<Parameter>();
foreach (XmlElement childNode in parameters.ChildNodes)
{
Parameters.Add(new Parameter {Name = childNode.LocalName, Value = childNode.FirstChild.Value});
}
}
}
public void WriteXml(XmlWriter writer)
{
writer.WriteElementString("Something", this.Something);
writer.WriteStartElement("Parameters");
foreach (var parameter in Parameters)
{
writer.WriteElementString(parameter.Name, parameter.Value);
}
writer.WriteEndElement();
}
}
Updated to include ReadXml implementation for deserialization
I'm not quite sure if the ReadXml is complete as I can't test this now, you might have to tweak it a bit for the Parameters
Try this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
Sample sample = new Sample(){
Something = "1234512345112345",
Parameters = new List<Parameter>(){
new Parameter(){
Name = new List<string>(){"Value", "Value"}
}
}
};
XmlSerializer serializer = new XmlSerializer(typeof(Sample));
StreamWriter writer = new StreamWriter(FILENAME);
serializer.Serialize(writer, sample);
writer.Flush();
writer.Close();
writer.Dispose();
XmlSerializer xs = new XmlSerializer(typeof(Sample));
XmlTextReader reader = new XmlTextReader(FILENAME);
Sample newSample = (Sample)xs.Deserialize(reader);
}
}
[XmlRoot("Sample")]
public class Sample
{
[XmlElement("Something")]
public string Something { get; set; }
[XmlElement("Parameters")]
public List<Parameter> Parameters { get; set; }
}
[XmlRoot("Parameters")]
public class Parameter
{
[XmlElement("Name")]
public List<string> Name { get; set; }
}
}
I want some Generic way to convert objects to xml nodes :
if i have some xml nodes like this:
<BusinessObject xmlns="http://xmlns.oracle.com/bpm/bpmobject/Data/BusinessObject"><?xml version="1.0" encoding="utf-16"?>
<BusinessObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<attribute1>sss</attribute1>
<attribute2>sss</attribute2>
</BusinessObject></BusinessObject>
I convert it to Json like that
{
"-xmlns": "http://xmlns.oracle.com/bpm/bpmobject/Data/BusinessObject",
"#text": "<?xml version=\"1.0\" encoding=\"utf-16\"?>
<BusinessObject xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">
<attribute1>sss</attribute1>
<attribute2>sss</attribute2>
</BusinessObject>"
}
Then to c# class:
public class Rootobject
{
public string xmlns { get; set; }
public string text { get; set; }
}
Now how to reverse it to xml nodes again after setting its value ? I want a general solution not for this example
XML serialization is what you are looking for
public class Rootobject
{
public string xmlns { get; set; }
public string text { get; set; }
}
public static void Main(string[] args)
{
Rootobject details = new Rootobject();
details.xmlns = "myNamespace";
details.text = "Value";
Serialize(details);
}
static public void Serialize(Rootobject details)
{
XmlSerializer serializer = new XmlSerializer(typeof(Rootobject));
using (TextWriter writer = new StreamWriter(#"C:\Xml.xml"))
{
serializer.Serialize(writer, details);
}
}
You can use XML Serialization for converting a Class to XML, and viceversa.
For reference, read C# Tutorial - XML Serialization.
You can also refer to XML Schema Definition Tool
Example:
[DataContract]
public class MyClass1 {
[DataMember]
public string name;
[DataMember]
public int age;
}
Serialize / Deserialize
MyClass1 obj = new MyClass1();
DataContractSerializer dcs = new DataContractSerializer(typeof(MyClass1));
using (Stream stream = new FileStream(#"C:\tmp\file.xml", FileMode.Create, FileAccess.Write))
{
using (XmlDictionaryWriter writer =
XmlDictionaryWriter.CreateTextWriter(stream, Encoding.UTF8))
{
writer.WriteStartDocument();
dcs.WriteObject(writer, obj);
}
}
I think you need to apply the Serializable attribute to your class to be able to serialize it. This makes sure that your class does not use some none serializable attributes.
[Serializable]
public class Rootobject
{
public string xmlns { get; set; }
public string text { get; set; }
}
This is my Model class:
public class ModelClass
{
public ModelClass()
{
}
public ModelClass(string operationName)
{
OperationName = operationName;
}
public string OperationName { get; set; }
public int Count { get; set; }
}
I have to serialize a list of this model class to a database table:
The table schema is:
ModelObjectContent (the serialized string)
IDModel
The method wich I use to serialize:
public static string SerializeObject(this List<ModelClass> toSerialize)
{
var xmlSerializer = new XmlSerializer(toSerialize.GetType());
var textWriter = new StringWriter();
xmlSerializer.Serialize(textWriter, toSerialize);
return textWriter.ToString();
}
When I save it to the database the string generated is like this:
<ArrayOfChartModel>
<ModelClass>
<OperationName>Chart1</OperationName>
<Count >1</Count>
</ModelClass>
<ModelClass>
<OperationName>Chart2</OperationName>
<Count >2</Count>
</ModelClass>
//etc
</ArrayOfChartModel>
The framework automattically creates a tag named ArrayOfChartModel and thats ok,
but my question is:
How to deserealize this xml to a list of ModelClass again?
This should work for you:
public static List<ModelClass> Deserialize(string xml)
{
var xmlSerializer = new XmlSerializer(typeof(ModelClass));
using (TextReader reader = new StringReader(xml))
{
return(List<ModelClass>)xmlSerializer.Deserialize(reader);
}
}
I'd like to serialize the following class to xml:
public class Survey
{
[XmlElement("edit")]
public string EditLink { get; set; }
}
As expected this serializes as (removed extra stuff not important to the question)
<Survey><edit>http://example.com/editlink</edit></Survey>
However, I'd like to prepend a parent node to the edit node, so that the resultant xml is:
<Survey><links><edit>http://example.com/editlink</edit></links></Survey>
Is there a way to do this with just the serialization attributes, without modifying the structure of the class?
You can't with that structure. If you expose EditLink as a collection then you can:
public class Survey
{
[XmlArray("links")]
[XmlArrayItem("edit")]
public string[] edit
{
get
{
return new [] {EditLink};
}
set
{
EditLink = value[0];
}
}
[XmlIgnore]
public string EditLink { get; set; }
}
Which yields:
<Survey>
<links>
<edit>http://example.com/editlink</edit>
</links>
</Survey>
You can try using the XMLSerializer class.
public class Survey
{
public string EditLink { get; set; }
}
private void SerializeSurvey()
{
XmlSerializer serializer = new XmlSerializer(typeof(Survey));
Survey survey = new Survey(){EditLink=""};
// Create an XmlTextWriter using a FileStream.
Stream fs = new FileStream(filename, FileMode.Create);
XmlWriter writer = new XmlTextWriter(fs, Encoding.Unicode);
// Serialize using the XmlTextWriter.
serializer.Serialize(writer, survey);
writer.Close();
}
I have the following C# class
[XmlRoot("Customer")]
public class MyClass
{
[XmlElement("CustId")]
public int Id {get;set;}
[XmlElement("CustName")]
public string Name {get;set;}
}
I then use the following function serialise the class object to Xml
public static XmlDocument SerializeObjectToXML(object obj, string sElementName)
{
XmlSerializer serializer =
new XmlSerializer(obj.GetType(), new XmlRootAttribute("Response"));
using (MemoryStream ms = new MemoryStream())
{
XmlDocument xmlDoc = new XmlDocument();
serializer.Serialize(ms, obj);
ms.Position = 0;
xmlDoc.Load(ms);
}
}
My current output to XML is like;
<Response>
<CustId></CustId>
<CustName></CustName>
</Response>
But how can I get the response to look like;
<Response>
<Customer>
<CustId></CustId>
<CustName></CustName>
</Customer>
</Response>
Change the XmlElementAttribute on MyClass (it's not actually valid there according to http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlelementattribute(v=vs.110).aspx) to an XmlTypeAttribute:
[XmlType("Customer")]
public class MyClass
{
[XmlElement("CustId")]
public int Id { get; set; }
[XmlElement("CustName")]
public string Name { get; set; }
}
The serialization method can now be (identical to that in the question but without the second parameter in the constructor of XmlSerializer):
public static XmlDocument SerializeObjectToXML(object obj, string sElementName)
{
XmlSerializer serializer = new XmlSerializer(obj.GetType());
XmlDocument xmlDoc = new XmlDocument();
using (MemoryStream ms = new MemoryStream())
{
serializer.Serialize(ms, obj);
ms.Position = 0;
xmlDoc.Load(ms);
}
return xmlDoc;
}
You can create a response object containing your customer, because that is what your desired xml shows as well.
[XmlRoot("Response")]
public class ResponseClass
{
[XmlElement("Customer")]
public Myclass Customer {get;set;}
}
You could define them like this:
public class MyClass
{
[XmlElement("Customer")]
public Customer cust { get; set; }
}
public class Customer
{
[XmlElement("CustId")]
public int Id { get; set; }
[XmlElement("CustName")]
public string Name { get; set; }
}
By the way, the [XmlElement("Customer")] is not valid on your example...