Omitting XML processing instruction when serializing an object - c#

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() { }
}

Related

Serialize(TextWriter, Object) vs Serialize(XmlWriter, Object)

The XmlSerializer.Serialize Method has overloads that accept TextWriter and XmlWriter.
My question is what are the practical differences between these two overloads in the follow examples? (list is a List<MyObjectModel>)
Example 1 (with TextWriter):
XmlSerializer serializer = new XmlSerializer(typeof(MyObjectModel));
using (TextWriter writer = new StreamWriter(savePath))
{
serializer.Serialize(writer, list);
}
Example 2 (with XmlWriter):
XmlSerializer serializer = new XmlSerializer(typeof(MyObjectModel));
using (XmlWriter writer = XmlWriter.Create(savePath))
{
serializer.Serialize(writer, list);
}
So far I've noticed that:
1) TextWriter seems to automatically perform indenting for you.
2) The default encoding for both is UTF-8.
I found the difference in the source code reference:
public void Serialize(TextWriter textWriter, object o, XmlSerializerNamespaces namespaces) {
XmlTextWriter xmlWriter = new XmlTextWriter(textWriter);
xmlWriter.Formatting = Formatting.Indented;
xmlWriter.Indentation = 2;
Serialize(xmlWriter, o, namespaces);
}
In short, the TextWriter overload uses a XmlTextWriter underneath the hood and sets the formatting for you.

Avoid XML Escape Double Quote

I'm currently trying to serialize a class into XML to be posted to php web service.
Whenever I did the normal serialization using XMLSerializer, XML declaration is always appear in the first line of the XML document (similar as to <?xml ....?>). I tested the XML and unable to get it working because the endpoint does not accept XML declaration and I can't do anything about it.
I'm unfamiliar with XML Serialization in C# to be honest.
Therefore, I used XMLWriter to do this as below :-
private string SerializeClassToString(GetRiskReport value)
{
var emptyNS = new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty });
var ser = new XmlSerializer(value.GetType());
var settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
using (var stream = new StringWriter())
{
using (var writer = XmlWriter.Create(stream, settings))
{
ser.Serialize(writer, value, emptyNS);
return stream.ToString();
}
}
}
Result for the Namespace is
<GetRiskReport FCRA=\"false\" ReturnResultsOnly=\"false\" Monitoring=\"false\">
... and I'm able to omit the XML Declaration, however I'm being introduced with 2 new problem.
I got \r\n for new line and I have escaped double quote such as ReturnResultsOnly=\"false\" Monitoring=\"false\" which is also unable processed by the endpoint.
I would like to ask is that does anyone can give me an idea on how to change the XmlWriterSetting to omit XML Declaration, avoid \r\n and also avoid escaped double quotes \"
Thanks for your advice in advance.
Simon
Try with following settings
settings.NewLineHandling = NewLineHandling.None;
settings.CheckCharacters = false;
private void SerializeClassToString(GetRiskReport value)
{
var emptyNS = new XmlSerializerNamespaces(new[]{XmlQualifiedName.Empty});
var ser = new XmlSerializer(value.GetType());
var settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
string path = 'your_file_path_here'
if (File.Exists(path)) File.Delete(path);
FileStream stream = File.Create(path);
using (var writer = XmlWriter.Create(stream, settings))
{
ser.Serialize(writer, value, emptyNS);
return;
}
}
There was no way to avoid ms bug or thier intensional specification about xmlserializing.It's easier and faster to use filestream object.

C# de-serialise Xml to object and serialise back to Xml again

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.

How to get Xml as string from XDocument?

I am new to LINQ to XML. After you have built XDocument, how do you get the OuterXml of it like you did with XmlDocument?
You only need to use the overridden ToString() method of the object:
XDocument xmlDoc ...
string xml = xmlDoc.ToString();
This works with all XObjects, like XElement, etc.
I don't know when this changed, but today (July 2017) when trying the answers out, I got
"System.Xml.XmlDocument"
Instead of ToString(), you can use the originally intended way accessing the XmlDocument content: writing the xml doc to a stream.
XmlDocument xml = ...;
string result;
using (StringWriter writer = new StringWriter())
{
xml.Save(writer);
result = writer.ToString();
}
Several responses give a slightly incorrect answer.
XDocument.ToString() omits the XML declaration (and, according to #Alex Gordon, may return invalid XML if it contains encoded unusual characters like &).
Saving XDocument to StringWriter will cause .NET to emit encoding="utf-16", which you most likely don't want (if you save XML as a string, it's probably because you want to later save it as a file, and de facto standard for saving files is UTF-8 - .NET saves text files as UTF-8 unless specified otherwise).
#Wolfgang Grinfeld's answer is heading in the right direction, but it's unnecessarily complex.
Use the following:
var memory = new MemoryStream();
xDocument.Save(memory);
string xmlText = Encoding.UTF8.GetString(memory.ToArray());
This will return XML text with UTF-8 declaration.
Doing XDocument.ToString() may not get you the full XML.
In order to get the XML declaration at the start of the XML document as a string, use the XDocument.Save() method:
var ms = new MemoryStream();
using (var xw = XmlWriter.Create(new StreamWriter(ms, Encoding.GetEncoding("ISO-8859-1"))))
new XDocument(new XElement("Root", new XElement("Leaf", "data"))).Save(xw);
var myXml = Encoding.GetEncoding("ISO-8859-1").GetString(ms.ToArray());
Use ToString() to convert XDocument into a string:
string result = string.Empty;
XElement root = new XElement("xml",
new XElement("MsgType", "<![CDATA[" + "text" + "]]>"),
new XElement("Content", "<![CDATA[" + "Hi, this is Wilson Wu Testing for you! You can ask any question but no answer can be replied...." + "]]>"),
new XElement("FuncFlag", 0)
);
result = root.ToString();
While #wolfgang-grinfeld's answer is technically correct (as it also produces the XML declaration, as opposed to just using .ToString() method), the code generated UTF-8 byte order mark (BOM), which for some reason XDocument.Parse(string) method cannot process and throws Data at the root level is invalid. Line 1, position 1. error.
So here is a another solution without the BOM:
var utf8Encoding =
new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
using (var memory = new MemoryStream())
using (var writer = XmlWriter.Create(memory, new XmlWriterSettings
{
OmitXmlDeclaration = false,
Encoding = utf8Encoding
}))
{
CompanyDataXml.Save(writer);
writer.Flush();
return utf8Encoding.GetString(memory.ToArray());
}
I found this example in the Microsoft .NET 6 documentation for XDocument.Save method. I think it answers the original question (what is the XDocument equivalent for XmlDocument.OuterXml), and also addresses the concerns that others have pointed out already. By using the XmlWritingSettings you can predictably control the string output.
https://learn.microsoft.com/en-us/dotnet/api/system.xml.linq.xdocument.save
StringBuilder sb = new StringBuilder();
XmlWriterSettings xws = new XmlWriterSettings();
xws.OmitXmlDeclaration = true;
xws.Indent = true;
using (XmlWriter xw = XmlWriter.Create(sb, xws)) {
XDocument doc = new XDocument(
new XElement("Child",
new XElement("GrandChild", "some content")
)
);
doc.Save(xw);
}
Console.WriteLine(sb.ToString());
Looking at these answers, I see a lot of unnecessary complexity and inefficiency in pursuit of generating the XML declaration automatically. But since the declaration is so simple, there isn't much value in generating it. Just KISS (keep it simple, stupid):
// Extension method
public static string ToStringWithDeclaration(this XDocument doc, string declaration = null)
{
declaration ??= "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n";
return declaration + doc.ToString();
}
// Usage
string xmlString = doc.ToStringWithDeclaration();
// Or
string xmlString = doc.ToStringWithDeclaration("...");
Using XmlWriter instead of ToString() can give you more control over how the output is formatted (such as if you want indentation), and it can write to other targets besides string.
The reason to target a memory stream is performance. It lets you skip the step of storing the XML in a string (since you know the data must end up in a different encoding eventually, whereas string is always UTF-16 in C#). For instance, for an HTTP request:
// Extension method
public static ByteArrayContent ToByteArrayContent(
this XDocument doc, XmlWriterSettings xmlWriterSettings = null)
{
xmlWriterSettings ??= new XmlWriterSettings();
using (var stream = new MemoryStream())
{
using (var writer = XmlWriter.Create(stream, xmlWriterSettings))
{
doc.Save(writer);
}
var content = new ByteArrayContent(stream.GetBuffer(), 0, (int)stream.Length);
content.Headers.ContentType = new MediaTypeHeaderValue("text/xml");
return content;
}
}
// Usage (XDocument -> UTF-8 bytes)
var content = doc.ToByteArrayContent();
var response = await httpClient.PostAsync("/someurl", content);
// Alternative (XDocument -> string -> UTF-8 bytes)
var content = new StringContent(doc.ToStringWithDeclaration(), Encoding.UTF8, "text/xml");
var response = await httpClient.PostAsync("/someurl", content);

How do I create an XmlNode from a call to XmlSerializer.Serialize?

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.

Categories