Im trying to Serialize an object( a class in this case) with an specific fomat.
I got something like this:
<ns:pay xmlns:ns="http://example.uri.here">
<ns:Payment>
<ns:customerKeyValue>5555</ns:customerKeyValue>
<ns:bankCode>BBBB</ns:bankCode>
<ns:paymentAmount>456</ns:paymentAmount>
<ns:paymentCategory>KD</ns:paymentCategory>
<ns:paymentMode>AC</ns:paymentMode>
<ns:referenceNumber>123A</ns:referenceNumber>
<ns:userID>Test2</ns:userID>
<ns:invoiceNumber>61</ns:invoiceNumber>
</ns:Payment>
</ns:pay>
I have the class that have each element but when i serialize it it convert its to this format:
<?xml version="1.0"?>
<ns_x003A_pay xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://example.uri.here">
<CustomerKeyValue>5555</CustomerKeyValue>
<BankCode>BBBB</BankCode>
<PaymentAmount>456</PaymentAmount>
<PaymentCategory>KD</PaymentCategory>
<PaymentMode>AC</PaymentMode>
<ReferenceNumber>123A</ReferenceNumber>
<UserID>Test2</UserID>
<InvoiceNumber>61</InvoiceNumber>
</ns_x003A_pay>
So anyone can help me with that?
The method that im using to convert to xml is this:
public static string SerializeToXMLString(object ObjectToSerialize)
{
MemoryStream mem = new MemoryStream();
System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(ObjectToSerialize.GetType());
ser.Serialize(mem, ObjectToSerialize);
ASCIIEncoding ascii = new ASCIIEncoding();
return ascii.GetString(mem.ToArray());
}
note:
to specify the namespace and class name i'm using this:
[XmlRootAttribute( "ns:pay", Namespace = "http://example.uri.here")]
in the class
If you haven't noted every XML element start with
Thanks for you help.
Ok guys I just found the answer here to my questions and i'm writing here to help people with this problem:
public static string SerializeToXMLString(object ObjectToSerialize)
{
//
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("ns", "http://example.uri.here");
//
//
XmlSerializer serializer = new XmlSerializer(ObjectToSerialize.GetType());
XmlWriterSettings writerSettings = new XmlWriterSettings();
writerSettings.OmitXmlDeclaration = true;
StringWriter stringWriter = new StringWriter();
using (XmlWriter xmlWriter = XmlWriter.Create(stringWriter, writerSettings))
{
serializer.Serialize(xmlWriter, ObjectToSerialize,ns);
}
return stringWriter.ToString();
}
To solve the prefix :
I created a XmlSerializerNamespaces object and added the prefix that I wanted and the namespace.
To solve the ns:pay ns:payment
I created two classes: Payment and Pay.
In the pay class i added this:
[XmlRoot("pay", Namespace = "http://example.uri.here")]
In the Payment Class i added this:
[XmlRoot("pay")]
Pay Class has a property of type payment. That create the xml in this style:
<ns:pay>
<ns:payment
element here
</ns:payemnt>
</ns:pay>
Thank you guys. Sorry that I ask and found the question almost 30 minutes after asking.
There is also LINQtoXSD (not XmlSerializer, sure :-)
Related
I would like to use JsonFx to convert XML to/from custom types and LINQ queries. Can anyone please provide an example to de-serialisation and serialisation back again?
Here's an example of the XML I'm working with.
XML pasted here: http://pastebin.com/wURiaJM2
JsonFx Supports several strategies of binding json to .net objects including dynamic objects. https://github.com/jsonfx/jsonfx
Kind regards
Si
PS I did try pasting the xml document into StackOverflow but it removed a lot of the documents quotes and XML declaration.
Here's a method that I have used. It may require some tweaking:
public static string SerializeObject<T>(T item, string rootName, Encoding encoding)
{
XmlWriterSettings writerSettings = new XmlWriterSettings();
writerSettings.OmitXmlDeclaration = true;
writerSettings.Indent = true;
writerSettings.NewLineHandling = NewLineHandling.Entitize;
writerSettings.IndentChars = " ";
writerSettings.Encoding = encoding;
StringWriter stringWriter = new StringWriter();
using (XmlWriter xml = XmlWriter.Create(stringWriter, writerSettings))
{
XmlAttributeOverrides aor = null;
if (rootName != null)
{
XmlAttributes att = new XmlAttributes();
att.XmlRoot = new XmlRootAttribute(rootName);
aor = new XmlAttributeOverrides();
aor.Add(typeof(T), att);
}
XmlSerializer xs = new XmlSerializer(typeof(T), aor);
XmlSerializerNamespaces xNs = new XmlSerializerNamespaces();
xNs.Add("", "");
xs.Serialize(xml, item, xNs);
}
return stringWriter.ToString();
}
And for Deserialization:
public static T DeserializeObject<T>(string xml)
{
using (StringReader rdr = new StringReader(xml))
{
return (T)new XmlSerializer(typeof(T)).Deserialize(rdr);
}
}
And call it like this:
string xmlString = Serialization.SerializeObject(instance, "Root", Encoding.UTF8);
ObjectType obj = Serialization.DeserializeObject<ObjectType>(xmlString);
Hope this helps. The rootName parameter in the Serialize method lets you customize the value of the root node in the resulting xml string. Also, your classes must be decorated with the proper Xml attributes which will control how an entity is serialized.
This post explains how to create an XSD and a Classes from an XML file and then covers serialisation and de-serialisation.
http://geekswithblogs.net/CWeeks/archive/2008/03/11/120465.aspx
Using this technique with the XSD.exe to create an XSD and then classes in a CS file I was able to serialisation and then de-serialisation back again.
However the serialisation process does not create an exact representation of the source XML, so there's still some post work to be done there.
Proper object disposal removed for brevity but I'm shocked if this is the simplest way to encode an object as UTF-8 in memory. There has to be an easier way doesn't there?
var serializer = new XmlSerializer(typeof(SomeSerializableObject));
var memoryStream = new MemoryStream();
var streamWriter = new StreamWriter(memoryStream, System.Text.Encoding.UTF8);
serializer.Serialize(streamWriter, entry);
memoryStream.Seek(0, SeekOrigin.Begin);
var streamReader = new StreamReader(memoryStream, System.Text.Encoding.UTF8);
var utf8EncodedXml = streamReader.ReadToEnd();
No, you can use a StringWriter to get rid of the intermediate MemoryStream. However, to force it into XML you need to use a StringWriter which overrides the Encoding property:
public class Utf8StringWriter : StringWriter
{
public override Encoding Encoding => Encoding.UTF8;
}
Or if you're not using C# 6 yet:
public class Utf8StringWriter : StringWriter
{
public override Encoding Encoding { get { return Encoding.UTF8; } }
}
Then:
var serializer = new XmlSerializer(typeof(SomeSerializableObject));
string utf8;
using (StringWriter writer = new Utf8StringWriter())
{
serializer.Serialize(writer, entry);
utf8 = writer.ToString();
}
Obviously you can make Utf8StringWriter into a more general class which accepts any encoding in its constructor - but in my experience UTF-8 is by far the most commonly required "custom" encoding for a StringWriter :)
Now as Jon Hanna says, this will still be UTF-16 internally, but presumably you're going to pass it to something else at some point, to convert it into binary data... at that point you can use the above string, convert it into UTF-8 bytes, and all will be well - because the XML declaration will specify "utf-8" as the encoding.
EDIT: A short but complete example to show this working:
using System;
using System.Text;
using System.IO;
using System.Xml.Serialization;
public class Test
{
public int X { get; set; }
static void Main()
{
Test t = new Test();
var serializer = new XmlSerializer(typeof(Test));
string utf8;
using (StringWriter writer = new Utf8StringWriter())
{
serializer.Serialize(writer, t);
utf8 = writer.ToString();
}
Console.WriteLine(utf8);
}
public class Utf8StringWriter : StringWriter
{
public override Encoding Encoding => Encoding.UTF8;
}
}
Result:
<?xml version="1.0" encoding="utf-8"?>
<Test xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<X>0</X>
</Test>
Note the declared encoding of "utf-8" which is what we wanted, I believe.
Your code doesn't get the UTF-8 into memory as you read it back into a string again, so its no longer in UTF-8, but back in UTF-16 (though ideally its best to consider strings at a higher level than any encoding, except when forced to do so).
To get the actual UTF-8 octets you could use:
var serializer = new XmlSerializer(typeof(SomeSerializableObject));
var memoryStream = new MemoryStream();
var streamWriter = new StreamWriter(memoryStream, System.Text.Encoding.UTF8);
serializer.Serialize(streamWriter, entry);
byte[] utf8EncodedXml = memoryStream.ToArray();
I've left out the same disposal you've left. I slightly favour the following (with normal disposal left in):
var serializer = new XmlSerializer(typeof(SomeSerializableObject));
using(var memStm = new MemoryStream())
using(var xw = XmlWriter.Create(memStm))
{
serializer.Serialize(xw, entry);
var utf8 = memStm.ToArray();
}
Which is much the same amount of complexity, but does show that at every stage there is a reasonable choice to do something else, the most pressing of which is to serialise to somewhere other than to memory, such as to a file, TCP/IP stream, database, etc. All in all, it's not really that verbose.
Very good answer using inheritance, just remember to override the initializer
public class Utf8StringWriter : StringWriter
{
public Utf8StringWriter(StringBuilder sb) : base (sb)
{
}
public override Encoding Encoding { get { return Encoding.UTF8; } }
}
I found this blog post which explains the problem very well, and defines a few different solutions:
(dead link removed)
I've settled for the idea that the best way to do it is to completely omit the XML declaration when in memory. It actually is UTF-16 at that point anyway, but the XML declaration doesn't seem meaningful until it has been written to a file with a particular encoding; and even then the declaration is not required. It doesn't seem to break deserialization, at least.
As #Jon Hanna mentions, this can be done with an XmlWriter created like this:
XmlWriter writer = XmlWriter.Create (output, new XmlWriterSettings() { OmitXmlDeclaration = true });
This is killing me. I've read these:
http://msdn.microsoft.com/en-us/library/athddy89(v=VS.80).aspx
http://msdn.microsoft.com/en-us/library/2baksw0z(v=VS.80).aspx
But I don't see how to apply them to what I'm trying to do. I want to customize the way the following list serializes...
[Serializable]
public class FinalConcentrations : List<string> { }
so that when I pass it as the "objectToSerialze" to this...
public void serializeObject(object objectToSerialize, Stream outputStream)
{
// removes the default added namespaces
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
XmlSerializer serial = new XmlSerializer(objectToSerialize.GetType());
MemoryStream ms = new MemoryStream();
serial.Serialize(ms, objectToSerialize, ns);
StreamReader reader = new StreamReader(ms);
ms.Position = 0;
ms.WriteTo(outputStream);
}
...it writes this to the output stream:
<FinalConcentrations>
<FinalConcentration>string value 1</FinalConcentration>
<FinalConcentration>string value 2</FinalConcentration>
<FinalConcentration>string value 3</FinalConcentration>
</FinalConcentration>
...instead of this
<FinalConcentrations>
<string>string value 1</string>
<string>string value 2</string>
<string>string value 3</string>
</FinalConcentration>
My serializeObject method is used to serialize a wide variety of objects, so I'm looking for a way to do this in my FinalConcentrations definition rather than within that method.
Please, help.
The easiest way to fix that is to pass in a wrapper object instead of the list itself, i.e.
public class FinalConcentrations {
private readonly List<string> items = new List<string>();
[XmlElement("FinalConcentration")]
public List<string> Items {get {return items;}}
}
that do?
Well, when I ran your example I actually got
<?xml version="1.0"?>
<ArrayOfString>
<string>Red</string>
<string>Green</string>
<string>Blue</string>
</ArrayOfString>
but by changing
[Serializable, XmlRoot( ElementName= "FinalConcentrations")]
public class FinalConcentrations : List<string> { }
I got
<?xml version="1.0"?>
<FinalConcentrations>
<string>Red</string>
<string>Green</string>
<string>Blue</string>
</FinalConcentrations>
QED?
There are a whole bunch of XML decorator attributes that can change the serialisation, eg. XmlElement. Worth having a look at.
Best of luck.
I'm serializing an object in a C# VS2003 / .Net 1.1 application. I need it serialized without the processing instruction, however. The XmlSerializer class puts out something like this:
<?xml version="1.0" encoding="utf-16" ?>
<MyObject>
<Property1>Data</Property1>
<Property2>More Data</Property2>
</MyObject>
Is there any way to get something like the following, without processing the resulting text to remove the tag?
<MyObject>
<Property1>Data</Property1>
<Property2>More Data</Property2>
</MyObject>
For those that are curious, my code looks like this...
XmlSerializer serializer = new XmlSerializer(typeof(MyObject));
StringBuilder builder = new StringBuilder();
using ( TextWriter stringWriter = new StringWriter(builder) )
{
serializer.Serialize(stringWriter, comments);
return builder.ToString();
}
I made a small correction
XmlSerializer serializer = new XmlSerializer(typeof(MyObject));
StringBuilder builder = new StringBuilder();
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
using ( XmlWriter stringWriter = XmlWriter.Create(builder, settings) )
{
serializer.Serialize(stringWriter, comments);
return builder.ToString();
}
In 2.0, you would use XmLWriterSettings.OmitXmlDeclaration, and serialize to an XmlWriter - however I don't think this exists in 1.1; so not entirely useful - but just one more "consider upgrading" thing... and yes, I realise it isn't always possible.
The following link will take you to a post where someone has a method of supressing the processing instruction by using an XmlWriter and getting into an 'Element' state rather than a 'Start' state. This causes the processing instruction to not be written.
Suppress Processing Instruction
If you pass an XmlWriter to the serializer, it will only emit a processing
instruction if the XmlWriter's state is 'Start' (i.e., has not had anything
written to it yet).
// Assume we have a type named 'MyType' and a variable of this type named
'myObject'
System.Text.StringBuilder output = new System.Text.StringBuilder();
System.IO.StringWriter internalWriter = new System.IO.StringWriter(output);
System.Xml.XmlWriter writer = new System.Xml.XmlTextWriter(internalWriter);
System.Xml.Serialization.XmlSerializer serializer = new
System.Xml.Serialization.XmlSerializer(typeof(MyType));
writer.WriteStartElement("MyContainingElement");
serializer.Serialize(writer, myObject);
writer.WriteEndElement();
In this case, the writer will be in a state of 'Element' (inside an element)
so no processing instruction will be written. One you finish writing the
XML, you can extract the text from the underlying stream and process it to
your heart's content.
What about omitting namespaces ?
instead of using
XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
namespaces.Add("", "");
ex:
<message xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">
If by "processing instruction" you mean the xml declaration, then you can avoid this by setting the OmitXmlDeclaration property of XmlWriterSettings. You'll need to serialize using an XmlWriter, to accomplish this.
XmlSerializer serializer = new XmlSerializer(typeof(MyObject));
StringBuilder builder = new StringBuilder();
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
using ( XmlWriter stringWriter = new StringWriter(builder, settings) )
{
serializer.Serialize(stringWriter, comments);
return builder.ToString();
}
But ah, this doesn't answer your question for 1.1. Well, for reference to others.
This works in .NET 1.1. (But you should still consider upgrading)
XmlSerializer s1= new XmlSerializer(typeof(MyClass));
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add( "", "" );
MyClass c= new MyClass();
c.PropertyFromDerivedClass= "Hallo";
sw = new System.IO.StringWriter();
s1.Serialize(new XTWND(sw), c, ns);
....
/// XmlTextWriterFormattedNoDeclaration
/// helper class : eliminates the XML Documentation at the
/// start of a XML doc.
/// XTWFND = XmlTextWriterFormattedNoDeclaration
public class XTWFND : System.Xml.XmlTextWriter
{
public XTWFND(System.IO.TextWriter w) : base(w) { Formatting = System.Xml.Formatting.Indented; }
public override void WriteStartDocument() { }
}
I am using a class library which represents some of its configuration in .xml. The configuration is read in using the XmlSerializer. Fortunately, the classes which represent the .xml use the XmlAnyElement attribute at which allows me to extend the configuration data for my own purposes without modifying the original class library.
<?xml version="1.0" encoding="utf-8"?>
<Config>
<data>This is some data</data>
<MyConfig>
<data>This is my data</data>
</MyConfig>
</Config>
This works well for deserialization. I am able to allow the class library to deserialize the .xml as normal and the I can use my own XmlSerializer instances with a XmlNodeReader against the internal XmlNode.
public class Config
{
[XmlElement]
public string data;
[XmlAnyElement]
public XmlNode element;
}
public class MyConfig
{
[XmlElement]
public string data;
}
class Program
{
static void Main(string[] args)
{
using (Stream fs = new FileStream(#"c:\temp\xmltest.xml", FileMode.Open))
{
XmlSerializer xser1 = new XmlSerializer(typeof(Config));
Config config = (Config)xser1.Deserialize(fs);
if (config.element != null)
{
XmlSerializer xser2 = new XmlSerializer(typeof(MyConfig));
MyConfig myConfig = (MyConfig)xser2.Deserialize(new XmlNodeReader(config.element));
}
}
}
I need to create a utility which will allow the user to generate a new configuration file that includes both the class library configuration as well my own configuration, so new objects will be created which were not read from the .xml file. The question is how can I serialize the data back into .xml?
I realize that I have to initially call XmlSerializer.Serialize on my data before calling the same method on the class library configuration. However, this requires that my data is represented by an XmlNode after calling Serialize. What is the best way to serialize an object into an XmlNode using the XmlSerializer?
Thanks,
-kevin
btw-- It looks like an XmlNodeWriter class written by Chris Lovett was available at one time from Microsoft, but the links are now broken. Does anyone know of an alternative location to get this class?
So you need to have your class contain custom configuration information, then serialize that class to XML, then make that serialized XML into an XML node: is that right?
Could you just take the string created by the XMLSerializer and wrap that in it's own XML tags?
XmlSerializer xs = new XmlSerializer(typeof(MyConfig));
StringWriter xout = new StringWriter();
xs.Serialize(xout, myConfig);
XmlDocument x = new XmlDocument();
x.LoadXml("<myConfig>" + xout.ToString() + "</myConfig>");
Now x is an XmlDocument containing one element, "<myconfig>", which has your serialized custom configuration in it.
Is that at all what you're looking for?
It took a bit of work, but the XPathNavigator route does work... just remember to call .Close on the XmlWriter, .Flush() doesn't do anything:
//DataContractSerializer serializer = new DataContractSerializer(typeof(foo));
XmlSerializer serializer = new XmlSerializer(typeof(foo));
XmlDocument doc = new XmlDocument();
XPathNavigator nav = doc.CreateNavigator();
XmlWriter writer = nav.AppendChild();
writer.WriteStartDocument();
//serializer.WriteObject(writer, new foo { bar = 42 });
serializer.Serialize(writer, new foo { bar = 42 });
writer.WriteEndDocument();
writer.Flush();
writer.Close();
Console.WriteLine(doc.OuterXml);
One solution is to serialize the inner object to a string and then load the string into a XmlDocument where you can find the XmlNode representing your data and attach it to the outer object.
XmlSerializer xser1 = new XmlSerializer(typeof(Config));
XmlSerializer xser2 = new XmlSerializer(typeof(MyConfig));
MyConfig myConfig = new MyConfig();
myConfig.data = "My special data";
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
XmlWriter xw = new XmlTextWriter(sw);
xser2.Serialize(xw, myConfig);
XmlDocument doc = new XmlDocument();
doc.LoadXml(sb.ToString());
Config config = new Config();
config.data = "some new info";
config.element = doc.LastChild;
xser1.Serialize(fs, config);
However, this solution is cumbersome and I would hope there is a better way, but it resolves my problem for now.
Now if I could just find the mythical XmlNodeWriter referred to on several blogs!
At least one resource points to this as an alternative to XmlNodeWriter: http://msdn.microsoft.com/en-us/library/5x8bxy86.aspx. Otherwise, you could write MS using that form they have on the new MSDN Code Library replacement for GotDotNet looking for XmlNodeWriter.