I am sending a request to a web service which requires a string containing XML, of which I have been giving an XSD.
I've ran xsd.exe and created a class based on this but am unsure of the best way to create the xml string to send, for example a stream, XMLDocument or some form of serialization.
UPDATE
I found this here
public static string XmlSerialize(object o)
{
using (var stringWriter = new StringWriter())
{
var settings = new XmlWriterSettings
{
Encoding = Encoding.GetEncoding(1252),
OmitXmlDeclaration = true
};
using (var writer = XmlWriter.Create(stringWriter, settings))
{
var xmlSerializer = new XmlSerializer(o.GetType());
xmlSerializer.Serialize(writer, o);
}
return stringWriter.ToString();
}
}
which lets me control the tag attribute.
What I am doing on several occasions is creating a class/struct to hold the data on the client-side program and serializing the data as a string. Then I make the web request and send it that XML string. Here is the code I use to serialize an object to XML:
public static string SerializeToString(object o)
{
string serialized = "";
System.Text.StringBuilder sb = new System.Text.StringBuilder();
//Serialize to memory stream
System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(o.GetType());
System.IO.TextWriter w = new System.IO.StringWriter(sb);
ser.Serialize(w, o);
w.Close();
//Read to string
serialized = sb.ToString();
return serialized;
}
As long as all the contents of the object are serializable it will serialize any object.
Use Xstream framework to generate an xml string. Hope this helps!
Here's what I have done before:
private static string CreateXMLString(object o)
{
XmlSerializer serializer = new XmlSerializer(typeof(object));
var stringBuilder = new StringBuilder();
using (var writer = XmlWriter.Create(stringBuilder))
{
serializer.Serialize(writer, o);
}
return stringBuilder.ToString();
}
Related
I am trying to serialize an object to XML and the problem that I am getting is that the object gets serialized to
<something />
instead of
<something/>
I believe that both are valid XML syntax, but I have to get <something/>
Here is my code
public static string Serialize<T>(T ObjectToSerialize)
{
XmlWriterSettings settings = new XmlWriterSettings()
{
OmitXmlDeclaration = true,
Encoding = Encoding.UTF8,
};
XmlSerializer xmlSerializer = new XmlSerializer(ObjectToSerialize.GetType());
using (StringWriter textWriter = new StringWriter())
{
using (var xw = XmlWriter.Create(textWriter, settings))
{
xmlSerializer.Serialize(xw, ObjectToSerialize);
}
return textWriter.ToString();
}
}
How can I fix it?
May not be the most efficient solution, but you could do a simple String.Replace before returning serialized data in Serialize<T>().
Replacing
return textWriter.ToString();
With
return textWriter.ToString().Replace(" />","/>");
Recently upgraded a 3.5 project to 4.5. There is a chunk of data that we are serializing and storing in the database, but everytime a save occurs in the upgraded project, the XML formatting has changed, throwing errors, and I can't seem to figure out the core issue. There are 2 SO questions in particular that mention encoding changes, but I've tried switching to UTF8 (in a few different ways specified in the answers on those questions), without any success - with UTF8 I just got a mess of strange characters throughout the entire file.
The main issues that I can see occurring are:
A leading ? character is added to the XML (which I've come to find out is a valid character, but we aren't handling apparently)
Child nodes aren't being included with some of the nodes.
Here is our serialization method:
public static string SerializeXml<T>(T instance)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
MemoryStream memStream = new MemoryStream();
XmlTextWriter xmlWriter = new XmlTextWriter(memStream, Encoding.Unicode);
serializer.Serialize(xmlWriter, instance);
memStream = (MemoryStream)xmlWriter.BaseStream;
return UnicodeEncoding.Unicode.GetString(memStream.ToArray()).Replace("<?xml version=\"1.0\" encoding=\"utf-16\"?>", "");
}
and our deserialization method:
public static T DeserializeXml<T>(string xml)
{
XmlSerializer xs = new XmlSerializer(typeof(T));
StringReader reader = new StringReader(xml);
return (T)xs.Deserialize(reader);
}
Any help would be appreciated, I am not too familiar with serialization or encoding. Just curious what may have changed with the upgrade to 4.5, or if there is something I need to take a closer look at.
If you want to Serialize to a String you need to use UTF16. If you want to Serialize with UTF8 you need to serialize to a byte[]. Strings in C# are UTF16 so in the code you posted I believe all your data is encoded with UTF16 but because you are omitting the Xml Declaration code assumes it is UTF8.
I would recommend using functions like this and not omitting the XmlDeclaration:
public static string SerializeXmlToString<T>(T instance)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
XmlWriterSettings settings = new XmlWriterSettings();
settings.Encoding = Encoding.Unicode;
StringBuilder builder = new StringBuilder();
using (StringWriter writer = new StringWriter(builder))
using (XmlWriter xmlWriter = XmlWriter.Create(writer, settings))
{
serializer.Serialize(xmlWriter, instance);
}
return builder.ToString();
}
public static byte[] SerializeXml<T>(T instance)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
XmlWriterSettings settings = new XmlWriterSettings();
settings.Encoding = Encoding.UTF8;
using (MemoryStream memStream = new MemoryStream())
{
using (XmlWriter xmlWriter = XmlWriter.Create(memStream, settings))
{
serializer.Serialize(xmlWriter, instance);
}
return memStream.ToArray();
}
}
public static T DeserializeXml<T>(string data)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
using (StringReader reader = new StringReader(data))
{
return (T)serializer.Deserialize(reader);
}
}
public static T DeserializeXml<T>(byte[] bytes)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
using(MemoryStream stream = new MemoryStream(bytes))
{
return (T)serializer.Deserialize(stream);
}
}
I seem to be getting some junk at the head of my serialized XML string. I have a simple extension method
public static string ToXML(this object This)
{
DataContractSerializer ser = new DataContractSerializer(This.GetType());
var settings = new XmlWriterSettings { Indent = true };
using (MemoryStream ms = new MemoryStream())
using (var w = XmlWriter.Create(ms, settings))
{
ser.WriteObject(w, This);
w.Flush();
return UTF8Encoding.Default.GetString(ms.ToArray());
}
}
and when I apply it to my object I get the string
<?xml version="1.0" encoding="utf-8"?>
<RootModelType xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/WeinCad.Data">
<MoineauPump xmlns:d2p1="http://schemas.datacontract.org/2004/07/Weingartner.Numerics">
<d2p1:Rotor>
<d2p1:Equidistance>0.0025</d2p1:Equidistance>
<d2p1:Lobes>2</d2p1:Lobes>
<d2p1:MajorRadius>0.04</d2p1:MajorRadius>
<d2p1:MinorRadius>0.03</d2p1:MinorRadius>
</d2p1:Rotor>
</MoineauPump>
</RootModelType>
Note the junk at the beginning. When I try to deserialize this
I get an error. If I copy paste the XML into my source minus
the junk prefix I can deserialize it. What is the junk text
and how can I remove it or handle it?
Note my deserialization code is
public static RootModelType Load(Stream data)
{
DataContractSerializer ser = new DataContractSerializer(typeof(RootModelType));
return (RootModelType)ser.ReadObject(data);
}
public static RootModelType Load(string data)
{
using(var stream = new MemoryStream(Encoding.UTF8.GetBytes(data))){
return Load(stream);
}
}
This fix seems to work
public static string ToXML(this object obj)
{
var settings = new XmlWriterSettings { Indent = true };
using (MemoryStream memoryStream = new MemoryStream())
using (StreamReader reader = new StreamReader(memoryStream))
using(XmlWriter writer = XmlWriter.Create(memoryStream, settings))
{
DataContractSerializer serializer =
new DataContractSerializer(obj.GetType());
serializer.WriteObject(writer, obj);
writer.Flush();
memoryStream.Position = 0;
return reader.ReadToEnd();
}
}
I have a custom type UserSettingConfig I want to save in my database, I want to save it as pure XML as the type might be changed later and migrating pure xml is easier than a binary objet.
public class Serialize
{
private readonly DataContractSerializer _serializer;
public Serialize()
{
_serializer = new DataContractSerializer(typeof(UserSettingConfig));
}
public string SerializeObject(UserSettingConfig userSettingConfig)
{
using (var memoryStream = new MemoryStream())
{
_serializer.WriteObject(memoryStream, userSettingConfig);
string userSettingXml = memoryStream.ToString();
memoryStream.Close();
return userSettingXml;
}
}
public UserSettingConfig DeSerializeObject(string userSettingXml)
{
UserSettingConfig userSettingConfig;
using (var stream = new MemoryStream(userSettingXml))
{
stream.Position = 0;
userSettingConfig = (UserSettingConfig)_serializer.ReadObject(stream);
}
return userSettingConfig;
}
}
This dont work as the Memory Stream want a byte array or int
I want my Serialize to return a string (I can save as varchar(MAX) in my database)
DataContractSerializer.WriteObject has an overload that takes an XmlWriter. You can construct one of those that writes the XML to a StringBuilder:
private static string SerializeToString(object objectToSerialize)
{
var serializer = new DataContractSerializer(objectToSerialize.GetType());
var output = new StringBuilder();
var xmlWriter = XmlWriter.Create(output);
serializer.WriteObject(xmlWriter, objectToSerialize);
xmlWriter.Close();
return output.ToString();
}
You may also consider serializing to JSON instead of XML, using the excellent JSON.NET library which can serialize even the most complex objects easily. JSON is very compact and is still readable.
To serialize:
string json = Newtonsoft.Json.JavaScriptConvert.SerializeObject(anySerializableObject);
To deserialize:
MyClass instance = (MyClass) Newtonsoft.Json.JavaScriptConvert.DeserializeObject(json, typeof(MyClass));
If you need xml without xml declaration, you should use XmlWriterSettings. For instance when you need xml string for node but not entire xml document.
private static string SerializeToString(object objectToSerialize)
{
var serializer = new DataContractSerializer(objectToSerialize.GetType());
var output = new StringBuilder();
var xmlWriter = XmlWriter.Create(output, new XmlWriterSettings() { OmitXmlDeclaration = true});
serializer.WriteObject(xmlWriter, objectToSerialize);
xmlWriter.Close();
return output.ToString();
}
Problem
By leveraging some samples I found online here, I've written some XML serialization methods.
Method1: Serialize an Object and return: (a) the type, (b) the xml string
Method2: Takes (a) and (b) above and gives you back the Object.
I noticed that the xml string from the Method1 contains a leading '?'. This seems to be fine when using Method2 to reconstruct the Object.
But when doing some testing in the application, sometimes we got leading '???' instead. This caused the Method2 to throw an exception while trying to reconstruct the Object.
The 'Object' in this case was just a simple int.
System.InvalidOperationException was unhandled
Message="There is an error in XML document (1, 1)."
Source="System.Xml"
StackTrace:
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle)
at System.Xml.Serialization.XmlSerializer.Deserialize(Stream stream)
at XMLSerialization.Program.DeserializeXmlStringToObject(String xmlString, String objectType) in C:\Documents and Settings\...Projects\XMLSerialization\Program.cs:line 96
at XMLSerialization.Program.Main(String[] args) in C:\Documents and Settings\...Projects\XMLSerialization\Program.cs:line 49
Would anyone be able to shed some light on what might be causing this?
Sample Code
Here's sample code from the mini-tester I wrote while coding this up which runs as a VS console app. It'll show you the XML string. You can also uncomment the regions to append the extra leading '??' to reproduce the exception.
using System;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace XMLSerialization
{
class Program
{
static void Main(string[] args)
{
// deserialize to string
#region int
object inObj = 5;
#endregion
#region string
//object inObj = "Testing123";
#endregion
#region list
//List inObj = new List();
//inObj.Add("0:25");
//inObj.Add("1:26");
#endregion
string[] stringArray = SerializeObjectToXmlString(inObj);
#region include leading ???
//int indexOfBracket = stringArray[0].IndexOf('<');
//stringArray[0] = "??" + stringArray[0];
#endregion
#region strip out leading ???
//int indexOfBracket = stringArray[0].IndexOf('<');
//string trimmedString = stringArray[0].Substring(indexOfBracket);
//stringArray[0] = trimmedString;
#endregion
Console.WriteLine("Input");
Console.WriteLine("-----");
Console.WriteLine("Object Type: " + stringArray[1]);
Console.WriteLine();
Console.WriteLine("XML String: " + Environment.NewLine + stringArray[0]);
Console.WriteLine(String.Empty);
// serialize back to object
object outObj = DeserializeXmlStringToObject(stringArray[0], stringArray[1]);
Console.WriteLine("Output");
Console.WriteLine("------");
#region int
Console.WriteLine("Object: " + (int)outObj);
#endregion
#region string
//Console.WriteLine("Object: " + (string)outObj);
#endregion
#region list
//string[] tempArray;
//List list = (List)outObj;
//foreach (string pair in list)
//{
// tempArray = pair.Split(':');
// Console.WriteLine(String.Format("Key:{0} Value:{1}", tempArray[0], tempArray[1]));
//}
#endregion
Console.Read();
}
private static string[] SerializeObjectToXmlString(object obj)
{
XmlTextWriter writer = new XmlTextWriter(new MemoryStream(), Encoding.UTF8);
writer.Formatting = Formatting.Indented;
XmlSerializer serializer = new XmlSerializer(obj.GetType());
serializer.Serialize(writer, obj);
MemoryStream stream = (MemoryStream)writer.BaseStream;
string xmlString = UTF8ByteArrayToString(stream.ToArray());
string objectType = obj.GetType().FullName;
return new string[]{xmlString, objectType};
}
private static object DeserializeXmlStringToObject(string xmlString, string objectType)
{
MemoryStream stream = new MemoryStream(StringToUTF8ByteArray(xmlString));
XmlSerializer serializer = new XmlSerializer(Type.GetType(objectType));
object obj = serializer.Deserialize(stream);
return obj;
}
private static string UTF8ByteArrayToString(Byte[] characters)
{
UTF8Encoding encoding = new UTF8Encoding();
return encoding.GetString(characters);
}
private static byte[] StringToUTF8ByteArray(String pXmlString)
{
UTF8Encoding encoding = new UTF8Encoding();
return encoding.GetBytes(pXmlString);
}
}
}
When I've come across this before, it usually had to do with encoding. I'd try specifying the encoding when you serialize your object. Try using the following code. Also, is there any specific reason why you need to return a string[] array? I've changed your methods to use generics so you don't have to specify a type.
private static string SerializeObjectToXmlString<T>(T obj)
{
XmlSerializer xmls = new XmlSerializer(typeof(T));
using (MemoryStream ms = new MemoryStream())
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Encoding = Encoding.UTF8;
settings.Indent = true;
settings.IndentChars = "\t";
settings.NewLineChars = Environment.NewLine;
settings.ConformanceLevel = ConformanceLevel.Document;
using (XmlWriter writer = XmlTextWriter.Create(ms, settings))
{
xmls.Serialize(writer, obj);
}
string xml = Encoding.UTF8.GetString(ms.ToArray());
return xml;
}
}
private static T DeserializeXmlStringToObject <T>(string xmlString)
{
XmlSerializer xmls = new XmlSerializer(typeof(T));
using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(xmlString)))
{
return (T)xmls.Deserialize(ms);
}
}
If you still have problems, try using Encoding.ASCII in your code anywhere you see Encoding.UTF8, unless you have a specific reason for using UTF8. I'm not sure of the cause, but I've seen UTF8 encoding cause this exact problem in certain cases when serializing.
This is BOM symbol. You can either remove it
if (xmlString.Length > 0 && xmlString[0] != '<')
{
xmlString = xmlString.Substring(1, xmlString.Length - 1);
}
Or use UTF32 to serialize
using (StringWriter writer = new StringWriter(CultureInfo.InvariantCulture))
{
serializer.Serialize(writer, instance);
result = writer.ToString();
}
And deserialize
object result;
using (StringReader reader = new StringReader(instance))
{
result = serializer.Deserialize(reader);
}
If you are using this code only inside .Net applications using UTF32 won't create problems as it's the default encoding for everything inside .Net