XmlSerializer and controlling namespace in XmlAnyElement - c#

using dotnet 2.0. Code to illustrate :
Class1 c1 = new Class1();
c1.SomeInt = 5;
XmlDocument doc = new XmlDocument();
doc.LoadXml("<anode xmlns=\"xyz\" ><id>123</id></anode>");
c1.Any = new XmlElement[1];
c1.Any[0] = (XmlElement)doc.DocumentElement;
XmlSerializer ser = new XmlSerializer(typeof(Class1));
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "xyz");
StringBuilder sb = new StringBuilder();
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
XmlWriter writer = XmlWriter.Create(sb, settings);
writer.WriteStartElement("root");
ser.Serialize(writer, c1, ns);
writer.WriteEndElement();
writer.Close();
string str = sb.ToString();
MessageBox.Show(str);
where Class1 is defined like :
[System.Serializable()]
[System.Xml.Serialization.XmlRoot(Namespace="xyz")]
public class Class1
{
private int someInt;
public int SomeInt
{
get { return someInt; }
set { someInt = value; }
}
private System.Xml.XmlElement[] anyField;
/// <remarks/>
[System.Xml.Serialization.XmlAnyElementAttribute()]
public System.Xml.XmlElement[] Any
{
get
{
return this.anyField;
}
set
{
this.anyField = value;
}
}
}
This code displays the string :
<root><Class1 xmlns="xyz"><SomeInt>5</SomeInt><anode xmlns="xyz"><id>123</id></anode></Class1></root>
This is the correct xml, but I'm wondering if this can be simplified.
What I would like is to not have the redundant xmlns="xyz" part in the "anode" element.
i.e. I would like :
<root><Class1 xmlns="xyz"><SomeInt>5</SomeInt><anode><id>123</id></anode></Class1></root>
Is this possible ?

No, I don't believe you can. You could use an aliased namespace as described in this article: Prettification of XML Serialization within Web Services.

settings.NamespaceHandling = NamespaceHandling.OmitDuplicates

Related

Control Array serialization without a collection class

I have this code:
public static void Main()
{
var test = new TestXML[] {new TestXML() {TestAttribute = "blah"}};
var settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
var ns = new XmlSerializerNamespaces();
ns.Add("abc", "a/b/c/d/e/f/g");
var serializer = new XmlSerializer(typeof(TestXML[]));
var sw = new StringWriter();
var xw = XmlWriter.Create(Console.Out, settings);
serializer.Serialize(xw,test,ns);
Console.ReadLine();
}
Continued...
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "a/b/c/d/e/f/g",IncludeInSchema = true)]
public class TestXML
{
public string TestAttribute { get; set; }
}
The code outputs:
<ArrayOfTestXML
xmlns:abc="a/b/c/d/e/f/g"><TestXML><abc:TestAttribute>blah</abc:TestAttribute></TestXML></ArrayOfTestXML>
We have a 3rd party dependency that limits our ability to add a collection class to the serialization process. Is it possible to control serialization so that <TestXML> gets the prefix, abc?
What about not to use standard XmlSerializer (which is good for cases where XML itself not have much constraints and used just for serialize/deserialize) and write own Serialization support for your classes?

Convert an object to an XML string

I have got a class named WebserviceType I got from the tool xsd.exe from an XSD file.
Now I want to deserialize an instance of an WebServiceType object to a string.
How can I do this?
The MethodCheckType object has as params a WebServiceType array.
My first try was like I serialized it: with a XmlSerializer and a StringWriter (while serializing I used a StringReader).
This is the method in which I serialize the WebServiceType object:
XmlSerializer serializer = new XmlSerializer(typeof(MethodCheckType));
MethodCheckType output = null;
StringReader reader = null;
// catch global exception, logg it and throw it
try
{
reader = new StringReader(path);
output = (MethodCheckType)serializer.Deserialize(reader);
}
catch (Exception)
{
throw;
}
finally
{
reader.Dispose();
}
return output.WebService;
Edit:
Maybe I could say it in different words: I have got an instance of this MethodCheckType object an on the other hand I have got the XML document from which I serialized this object. Now I want to convert this instance into a XML document in form of a string. After this I have to proof if both strings (of XML documents) are the same. This I have to do, because I make unit tests of the first method in which I read an XML document into a StringReader and serialize it into a MethodCheckType object.
Here are conversion method for both ways.
this = instance of your class
public string ToXML()
{
using(var stringwriter = new System.IO.StringWriter())
{
var serializer = new XmlSerializer(this.GetType());
serializer.Serialize(stringwriter, this);
return stringwriter.ToString();
}
}
public static YourClass LoadFromXMLString(string xmlText)
{
using(var stringReader = new System.IO.StringReader(xmlText))
{
var serializer = new XmlSerializer(typeof(YourClass ));
return serializer.Deserialize(stringReader) as YourClass ;
}
}
I realize this is a very old post, but after looking at L.B's response I thought about how I could improve upon the accepted answer and make it generic for my own application. Here's what I came up with:
public static string Serialize<T>(T dataToSerialize)
{
try
{
var stringwriter = new System.IO.StringWriter();
var serializer = new XmlSerializer(typeof(T));
serializer.Serialize(stringwriter, dataToSerialize);
return stringwriter.ToString();
}
catch
{
throw;
}
}
public static T Deserialize<T>(string xmlText)
{
try
{
var stringReader = new System.IO.StringReader(xmlText);
var serializer = new XmlSerializer(typeof(T));
return (T)serializer.Deserialize(stringReader);
}
catch
{
throw;
}
}
These methods can now be placed in a static helper class, which means no code duplication to every class that needs to be serialized.
public static string Serialize(object dataToSerialize)
{
if(dataToSerialize==null) return null;
using (StringWriter stringwriter = new System.IO.StringWriter())
{
var serializer = new XmlSerializer(dataToSerialize.GetType());
serializer.Serialize(stringwriter, dataToSerialize);
return stringwriter.ToString();
}
}
public static T Deserialize<T>(string xmlText)
{
if(String.IsNullOrWhiteSpace(xmlText)) return default(T);
using (StringReader stringReader = new System.IO.StringReader(xmlText))
{
var serializer = new XmlSerializer(typeof(T));
return (T)serializer.Deserialize(stringReader);
}
}
public static class XMLHelper
{
/// <summary>
/// Usage: var xmlString = XMLHelper.Serialize<MyObject>(value);
/// </summary>
/// <typeparam name="T">Kiểu dữ liệu</typeparam>
/// <param name="value">giá trị</param>
/// <param name="omitXmlDeclaration">bỏ qua declare</param>
/// <param name="removeEncodingDeclaration">xóa encode declare</param>
/// <returns>xml string</returns>
public static string Serialize<T>(T value, bool omitXmlDeclaration = false, bool omitEncodingDeclaration = true)
{
if (value == null)
{
return string.Empty;
}
try
{
var xmlWriterSettings = new XmlWriterSettings
{
Indent = true,
OmitXmlDeclaration = omitXmlDeclaration, //true: remove <?xml version="1.0" encoding="utf-8"?>
Encoding = Encoding.UTF8,
NewLineChars = "", // remove \r\n
};
var xmlserializer = new XmlSerializer(typeof(T));
using (var memoryStream = new MemoryStream())
{
using (var xmlWriter = XmlWriter.Create(memoryStream, xmlWriterSettings))
{
xmlserializer.Serialize(xmlWriter, value);
//return stringWriter.ToString();
}
memoryStream.Position = 0;
using (var sr = new StreamReader(memoryStream))
{
var pureResult = sr.ReadToEnd();
var resultAfterOmitEncoding = ReplaceFirst(pureResult, " encoding=\"utf-8\"", "");
if (omitEncodingDeclaration)
return resultAfterOmitEncoding;
return pureResult;
}
}
}
catch (Exception ex)
{
throw new Exception("XMLSerialize error: ", ex);
}
}
private static string ReplaceFirst(string text, string search, string replace)
{
int pos = text.IndexOf(search);
if (pos < 0)
{
return text;
}
return text.Substring(0, pos) + replace + text.Substring(pos + search.Length);
}
}
This is my solution, for any list object you can use this code for convert to xml layout. KeyFather is your principal tag and KeySon is where start your Forech.
public string BuildXml<T>(ICollection<T> anyObject, string keyFather, string keySon)
{
var settings = new XmlWriterSettings
{
Indent = true
};
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(T));
StringBuilder builder = new StringBuilder();
using (XmlWriter writer = XmlWriter.Create(builder, settings))
{
writer.WriteStartDocument();
writer.WriteStartElement(keyFather);
foreach (var objeto in anyObject)
{
writer.WriteStartElement(keySon);
foreach (PropertyDescriptor item in props)
{
writer.WriteStartElement(item.DisplayName);
writer.WriteString(props[item.DisplayName].GetValue(objeto).ToString());
writer.WriteEndElement();
}
writer.WriteEndElement();
}
writer.WriteFullEndElement();
writer.WriteEndDocument();
writer.Flush();
return builder.ToString();
}
}

Problems serializing a class to XML and including a CDATA section

I have a class that is serialized into XML for consumption by a web service. In this classes instance the XML must include a CDATA section for the web service to read it but I am at a loss on how to implement this.
The XML needs to look like:
<UpdateOrderStatus>
<Action>2</Action>
<Value>
<![CDATA[
<Shipment>
<Header>
<SellerID>
...
]]>
</Value>
</UpdateOrderStatus>
I am able to generate the appropriate XML, except for the CDATA part.
My class structure looks like:
public class UpdateOrderStatus
{
public int Action { get; set; }
public ValueInfo Value { get; set; }
public UpdateOrderStatus()
{
Value = new ValueInfo();
}
public class ValueInfo
{
public ShipmentInfo Shipment { get; set; }
public ValueInfo()
{
Shipment = new ShipmentInfo();
}
public class ShipmentInfo
{
public PackageListInfo PackageList { get; set; }
public HeaderInfo Header { get; set; }
public ShipmentInfo()
{
PackageList = new PackageListInfo();
Header = new HeaderInfo();
}
....
I have seen some suggestions on using:
[XmlElement("node", typeof(XmlCDataSection))]
but that causes an exception
I have also tried
[XmlElement("Value" + "<![CDATA[")]
but the resulting XML is incorrect showing
<Value_x003C__x0021__x005B_CDATA_x005B_>
....
</Value_x003C__x0021__x005B_CDATA_x005B_>
Can anyone show me what I am doing wrong, or where I need to go with this?
--Edit--
making shipmentInfo serializable per carlosfigueira works for the most part, however I get extra ? characters in the resulting XML ( see post Writing an XML fragment using XmlWriterSettings and XmlSerializer is giving an extra character for details )
As such I changed the Write XML method to:
public void WriteXml(XmlWriter writer)
{
using (MemoryStream ms = new MemoryStream())
{
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
settings.Encoding = new UnicodeEncoding(bigEndian: false, byteOrderMark: false);
settings.Indent = true;
using (XmlWriter innerWriter = XmlWriter.Create(ms, settings))
{
shipmentInfoSerializer.Serialize(innerWriter, this.Shipment,ns);
innerWriter.Flush();
writer.WriteCData(Encoding.UTF8.GetString(ms.ToArray()));
}
}
}
However I am not getting an exception:
System.InvalidOperationException: There was an error generating the XML document. ---> System.ArgumentException: '.', hexadecimal
value 0x00, is an invalid character.
--Edit --
The exception was caused by the inclusion of my previous serializeToString method. Since removing that the CDATA output is correct, except for a spacing issue, but I am also getting a namespace and xml declaration that should be removed by the XML settings specified. Output is:
<?xml version="1.0"?>
<UpdateOrderStatus xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Action>1</Action>
<Value><![CDATA[< S h i p m e n t I n f o >
< P a c k a g e L i s t >
< P a c k a g e >
< S h i p D a t e > 2 0 1 2 - 0 7 - 1 3 T 1 1 : 5 8 : 5 1 . 0 9 2 5 6 1 5 - 0 4 : 0 0 < / S h i p D a t e >
< I t e m L i s t >
< I t e m >
< S h i p p e d Q t y > 0 < / S h i p p e d Q t y >
< / I t e m >
< / I t e m L i s t >
< / P a c k a g e >
< / P a c k a g e L i s t >
< H e a d e r >
< S e l l e r I d > S h i p m e n t h e a d e r < / S e l l e r I d >
< S O N u m b e r > 0 < / S O N u m b e r >
< / H e a d e r >
< / S h i p m e n t I n f o > ]]></Value>
</UpdateOrderStatus>
Any ideas of avoiding the BOM using the new class?
--Edit 3 -- SUCCESS!
I have implemented changes suggested below and now have the following writer class and test methods:
UpdateOrderStatus obj = new UpdateOrderStatus();
obj.Action = 1;
obj.Value = new UpdateOrderStatus.ValueInfo();
obj.Value.Shipment = new UpdateOrderStatus.ValueInfo.ShipmentInfo();
obj.Value.Shipment.Header.SellerId = "Shipment header";
obj.Value.Shipment.PackageList = new UpdateOrderStatus.ValueInfo.ShipmentInfo.PackageListInfo();
obj.Value.Shipment.PackageList.Package = new UpdateOrderStatus.ValueInfo.ShipmentInfo.PackageListInfo.PackageInfo();
obj.Value.Shipment.PackageList.Package.ShipDate = DateTime.Now;
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
settings.Encoding = new UTF8Encoding(false);
settings.Indent = true;
XmlSerializer xs = new XmlSerializer(typeof(UpdateOrderStatus));
MemoryStream ms = new MemoryStream();
XmlWriter writer = XmlWriter.Create(ms, settings);
xs.Serialize(writer, obj, ns);
Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));
}
public void WriteXml(XmlWriter writer)
{
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
settings.Indent = true;
StringBuilder sb = new StringBuilder();
using (XmlWriter innerWriter = XmlWriter.Create(sb, settings))
{
shipmentInfoSerializer.Serialize(innerWriter, this.Shipment, ns);
innerWriter.Flush();
writer.WriteCData(sb.ToString());
}
}
This produces the following XML:
<UpdateOrderStatus>
<Action>1</Action>
<Value><![CDATA[<ShipmentInfo>
<PackageList>
<Package>
<ShipDate>2012-07-13T14:05:36.6170802-04:00</ShipDate>
<ItemList>
<Item>
<ShippedQty>0</ShippedQty>
</Item>
</ItemList>
</Package>
</PackageList>
<Header>
<SellerId>Shipment header</SellerId>
<SONumber>0</SONumber>
</Header>
</ShipmentInfo>]]></Value>
</UpdateOrderStatus>
In response to the 'spaces' you are seeing after your edit, it is because of the encoding you are using (Unicode, 2 bytes per character).
Try:
settings.Encoding = new Utf8Encoding(false);
EDIT:
Also, note that format of the MemoryStream is not necessarily a valid UTF-8 encoded string! You can use a StringBuilder instead of MemoryStream to create your inner writer.
public void WriteXml(XmlWriter writer)
{
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
settings.Indent = true;
StringBuilder sb = new StringBuilder();
using (XmlWriter innerWriter = XmlWriter.Create(sb, settings))
{
shipmentInfoSerializer.Serialize(innerWriter, this.Shipment,ns);
innerWriter.Flush();
writer.WriteCData(sb.ToString());
}
}
Could this be of any help: http://msdn.microsoft.com/en-us/library/system.xml.xmldocument.createcdatasection.aspx
//Create a CData section.
XmlCDataSection CData;
CData = doc.CreateCDataSection("All Jane Austen novels 25% off starting 3/23!");
//Add the new node to the document.
XmlElement root = doc.DocumentElement;
root.AppendChild(CData);
Console.WriteLine("Display the modified XML...");
doc.Save(Console.Out);
Also, what Exception did you get when using the attribute?
-- edit --
You could try adding a custom class, and do something like this:
some xml serializable class,
{
.......
[XmlElement("PayLoad", Type=typeof(CDATA))]
public CDATA PayLoad
{
get { return _payLoad; }
set { _payLoad = value; }
}
}
public class CDATA : IXmlSerializable
{
private string text;
public CDATA()
{}
public CDATA(string text)
{
this.text = text;
}
public string Text
{
get { return text; }
}
/// <summary>
/// Interface implementation not used here.
/// </summary>
XmlSchema IXmlSerializable.GetSchema()
{
return null;
}
/// <summary>
/// Interface implementation, which reads the content of the CDATA tag
/// </summary>
void IXmlSerializable.ReadXml(XmlReader reader)
{
this.text = reader.ReadElementString();
}
/// <summary>
/// Interface implementation, which writes the CDATA tag to the xml
/// </summary>
void IXmlSerializable.WriteXml(XmlWriter writer)
{
writer.WriteCData(this.text);
}
}
As found here http://bytes.com/topic/net/answers/530724-cdata-xmltextattribute
Implementing ShipmentInfo as an IXmlSerializable type will get close to what you need - see example below.
public class StackOverflow_11471676
{
public class UpdateOrderStatus
{
public int Action { get; set; }
public ValueInfo Value { get; set; }
}
[XmlType(TypeName = "Shipment")]
public class ShipmentInfo
{
public string Header { get; set; }
public string Body { get; set; }
}
public class ValueInfo : IXmlSerializable
{
public ShipmentInfo Shipment { get; set; }
private XmlSerializer shipmentInfoSerializer = new XmlSerializer(typeof(ShipmentInfo));
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
using (MemoryStream ms = new MemoryStream(
Encoding.UTF8.GetBytes(
reader.ReadContentAsString())))
{
Shipment = (ShipmentInfo)this.shipmentInfoSerializer.Deserialize(ms);
}
}
public void WriteXml(XmlWriter writer)
{
using (MemoryStream ms = new MemoryStream())
{
using (XmlWriter innerWriter = XmlWriter.Create(ms, new XmlWriterSettings { OmitXmlDeclaration = true }))
{
shipmentInfoSerializer.Serialize(innerWriter, this.Shipment);
innerWriter.Flush();
writer.WriteCData(Encoding.UTF8.GetString(ms.ToArray()));
}
}
}
}
public static void Test()
{
UpdateOrderStatus obj = new UpdateOrderStatus
{
Action = 1,
Value = new ValueInfo
{
Shipment = new ShipmentInfo
{
Header = "Shipment header",
Body = "Shipment body"
}
}
};
XmlSerializer xs = new XmlSerializer(typeof(UpdateOrderStatus));
MemoryStream ms = new MemoryStream();
xs.Serialize(ms, obj);
Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));
}
}
The below example is only when the structure of the schema is defined and you have no choice of altering the schema.
When you Deserialize/Serialize a [xmltext] value it is very difficult to hold the text in the CDATA[]
enclose. you can use compiletransform to get the CDATA value in the xml as it is but the CDATA is lost as soon as you deserialize in C# and load to memory stuff.
This is one of the easiest way to do
deserialize/Serialize
once the final xml output is derived. The final xml can be
converted to string and parsed as shown below and return it as
string will embed CDATA to the test1 value.
string xml ="<test><test1>###!#!#!##!##%$%##$%#$%</test1></test>";
XNamespace ns = #"";
XDocument doc = XDocument.Parse(xml);
string xmlString = string.Empty;
var coll = from query in doc.Descendants(ns + "test1")
select query;
foreach (var value in coll){
value.ReplaceNodes(new XCData(value .Value));
}
doc.save("test.xml");// convert doc.tostring()
I think carlosfigueira just gave an elegant answer, but perhaps a little hard to understand at first sight. Here is an alternative for your consideration, you can Serialize/Deserialize UpdateOrderStatus and ShipmentInfo separately.
Define your business object class as:
[XmlRoot("UpdateOrderStatus")]
public class UpdateOrderStatus
{
[XmlElement("Action")]
public int Action { get; set; }
private String valueField;
[XmlElement("Value")]
public XmlCDataSection Value
{
get
{
XmlDocument xmlDoc = new XmlDocument();
return xmlDoc.CreateCDataSection(valueField);
}
set
{
this.valueField = value.Value;
}
}
[XmlIgnore]
public ShipmentInfo Shipment
{
get;
set;
}
}
[XmlRoot("ShipmentInfo")]
public class ShipmentInfo
{
[XmlElement("Package")]
public String Package { get; set; }
[XmlElement("Header")]
public String Header { get; set; }
}
Note that you should use XmlCDataSection for the Value field.
Here is the test/helper functions:
// Test function
const string t = #"<UpdateOrderStatus>
<Action>2</Action>
<Value>
<![CDATA[<ShipmentInfo>
<Package>packageInfo</Package>
<Header>headerInfo</Header>
</ShipmentInfo>]]>
</Value>
</UpdateOrderStatus>";
static void Test1()
{
UpdateOrderStatus os = Deserialize(t);
String t2 = XmlUtil.Serialize(os);
}
// Helper functions
static UpdateOrderStatus Deserialize(String str)
{
UpdateOrderStatus os = XmlUtil.DeserializeString<UpdateOrderStatus>(str);
os.Shipment = XmlUtil.DeserializeString<ShipmentInfo>(os.Value.InnerText);
return os;
}
public static class XmlUtil
{
public static String Serialize<T>(T o)
{
XmlSerializer s = new XmlSerializer(typeof(T)); //, overrides);
//StringBuilder builder = new StringBuilder();
MemoryStream ms = new MemoryStream();
XmlWriterSettings settings = new XmlWriterSettings();
settings.Encoding = Encoding.UTF8;
settings.Indent = true;
using (XmlWriter xmlWriter = XmlWriter.Create(ms, settings))
{
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add(String.Empty, String.Empty);
s.Serialize(xmlWriter, o, ns);
}
Byte[] bytes = ms.ToArray();
// discard the BOM part
Int32 idx = settings.Encoding.GetPreamble().Length;
return Encoding.UTF8.GetString(bytes, idx, bytes.Length - idx);
}
public static T DeserializeString<T>(String content)
{
using (TextReader reader = new StringReader(content))
{
XmlSerializer s = new XmlSerializer(typeof(T));
return (T)s.Deserialize(reader);
}
}
...
}

XmlSerializer.Serialize Stripping the <xml> tag

I am trying to get communicate to a payment processor. When I use XmlSerializer.Serialize
on my object I get
<?xml version=\"1.0\" encoding=\"utf-16\"?>
<txn xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">
<ssl_merchant_id>xxxxxx</ssl_merchant_id>
<ssl_user_id>xxxxxx</ssl_user_id>
<ssl_pin>xxxxxx</ssl_pin>
<ssl_test_mode>True</ssl_test_mode>
<ssl_transaction_type>ccavsonly</ssl_transaction_type>
<ssl_card_number>4111111111111111</ssl_card_number>
<ssl_exp_date>0612</ssl_exp_date>
<ssl_avs_address>101 Main St.</ssl_avs_address>
<ssl_avs_zip>90210</ssl_avs_zip>
</txn>
Prior to using that method, I manually built the XML for testing and this worked:
<txn>
<ssl_merchant_id>xxxxxx</ssl_merchant_id>
<ssl_user_id>xxxxxx</ssl_user_id>
<ssl_pin>xxxxxx</ssl_pin>
<ssl_test_mode>True</ssl_test_mode>
<ssl_transaction_type>ccavsonly</ssl_transaction_type>
<ssl_card_number>4111111111111111</ssl_card_number>
<ssl_exp_date>0612</ssl_exp_date>
<ssl_avs_address>101 Main St.</ssl_avs_address>
<ssl_avs_zip>90210</ssl_avs_zip>
</txn>
How would I go about stripping out the <?xml version=\"1.0\" encoding=\"utf-16\"?> and xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"> from the XML or not have the serializer generate it to begin with?
My object looks like:
[XmlRoot(ElementName="txn")]
public class AvsTransmission
{
[XmlElement]
public string ssl_merchant_id { get; set; }
[XmlElement]
public string ssl_user_id { get; set; }
[XmlElement]
public string ssl_pin { get; set; }
[XmlElement]
public string ssl_test_mode { get; set; }
[XmlElement]
public string ssl_transaction_type { get; set; }
[XmlElement]
public string ssl_card_number { get; set; }
[XmlElement]
public string ssl_exp_date { get; set; }
[XmlElement]
public string ssl_avs_address { get; set; }
[XmlElement]
public string ssl_avs_zip { get; set; }
}
My first answer was only half of the problem, you also have to remove the declaration as has been mentioned.
Here is an example:
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
MemoryStream ms = new MemoryStream();
XmlWriter writer = XmlWriter.Create(ms, settings);
XmlSerializerNamespaces names = new XmlSerializerNamespaces();
names.Add("", "");
XmlSerializer cs = new XmlSerializer(typeof(Cat));
cs.Serialize(writer, new Cat { Lives = 9 }, names);
ms.Flush();
ms.Seek(0, SeekOrigin.Begin);
StreamReader sr = new StreamReader(ms);
var xml = sr.ReadToEnd();
The string xml now contains:
<cat><Lives>9</Lives></cat>
First function convert object to xml string, the second one convert object and write xml to file simultaneously.
public static string Serialize<T>(T obj)
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
var writer = new StringWriter();
XmlWriter xmlWriter = XmlWriter.Create(writer, settings);
XmlSerializerNamespaces names = new XmlSerializerNamespaces();
names.Add("", "");
XmlSerializer serializer = new XmlSerializer(typeof(T));
serializer.Serialize(xmlWriter, obj, names);
var xml = writer.ToString();
return xml;
}
public static void Serialize<T>(T obj, string filepath)
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
var writer = new StreamWriter(filepath);
XmlWriter xmlWriter = XmlWriter.Create(writer, settings);
XmlSerializerNamespaces names = new XmlSerializerNamespaces();
names.Add("", "");
XmlSerializer serializer = new XmlSerializer(typeof(T));
serializer.Serialize(xmlWriter, obj, names);
}
Actually I realized that code repeat yourself. In these methods, change only one thing which is writer object, so the code must be like below. In these way, you can easily use code just by changing writer object type.
public static string Serialize<T>(T obj)
{
var writer = new StringWriter();
Serialize<T>(obj,writer);
var xml = writer.ToString();
return xml;
}
public static void Serialize<T>(T obj, string filepath)
{
var writer = new StreamWriter(filepath);
Serialize<T>(obj,writer);
}
public static void Serialize<T>(T obj, TextWriter writer)
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
XmlWriter xmlWriter = XmlWriter.Create(writer, settings);
XmlSerializerNamespaces names = new XmlSerializerNamespaces();
names.Add("", "");
XmlSerializer serializer = new XmlSerializer(typeof(T));
serializer.Serialize(xmlWriter, obj, names);
}
Very similar to #payo's orignal answer:
If you want to remove the namespace you may also want to remove the version, to save you searching I've added that functionality so the below code will do both.
I've also wrapped it in a generic method as I'm creating very large xml files which are too large to serialize in memory so I've broken my output file down and serialize it in smaller "chunks":
public string XmlSerialize<T>(T entity) where T : class
{
// removes version
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
XmlSerializer xsSubmit = new XmlSerializer(typeof(T));
StringWriter sw = new StringWriter();
using (XmlWriter writer = XmlWriter.Create(sw, settings))
{
// removes namespace
var xmlns = new XmlSerializerNamespaces();
xmlns.Add(string.Empty, string.Empty);
xsSubmit.Serialize(writer, entity, xmlns);
return sw.ToString(); // Your XML
}
}
If you use XmlWriter there is a setting to omit the declaration
http://msdn.microsoft.com/en-us/library/system.xml.xmlwritersettings.omitxmldeclaration.aspx
I'll work on an example, but that might be enough to get you going.
EDIT: Here's a sample that runs in LinqPad
string test = "test";
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
MemoryStream strm = new MemoryStream();
XmlWriter writer = XmlWriter.Create(strm, settings);
XmlSerializer serializer = new XmlSerializer(typeof(string));
serializer.Serialize(writer, test);
strm.Position = 0;
StreamReader reader = new StreamReader(strm);
var x = reader.ReadToEnd();
x.Dump();
writer.Close();
reader.Close();
strm.Close();
Output
<string>test</string>
Comment out line 3 and the Output is
<?xml version="1.0" encoding="utf-8"?><string>test</string>
Just to simplify the soln. of the original problem of removing UTF encoding declaration
here is the code
StringBuilder sb = new StringBuilder();
var serializer = new System.Xml.Serialization.XmlSerializer(typeToSerialize.GetType());
serializer.Serialize(System.Xml.XmlWriter.Create(sb, new System.Xml.XmlWriterSettings { OmitXmlDeclaration = true, Indent=true }), typeToSerialize);

not able to Deserialize xml into object

I am having following peice of code ,where in i am trying to serialize and deserailize object of StringResource class.
Please note Resource1.stringXml = its coming from resource file.If i pass strelemet.outerXMl i get the object from Deserialize object ,but if i pass Resource1.stringXml i am getting following exception
{"< STRING xmlns=''> was not expected."} System.Exception {System.InvalidOperationException}
class Program
{
static void Main(string[] args)
{
StringResource str = new StringResource();
str.DELETE = "CanDelete";
str.ID= "23342";
XmlElement strelemet = SerializeObjectToXmlNode (str);
StringResource strResourceObject = DeSerializeXmlNodeToObject<StringResource>(Resource1.stringXml);
Console.ReadLine();
}
public static T DeSerializeXmlNodeToObject<T>(string objectNodeOuterXml)
{
try
{
TextReader objStringsTextReader = new StringReader(objectNodeOuterXml);
XmlSerializer stringResourceSerializer = new XmlSerializer(typeof(T),string.Empty);
return (T)stringResourceSerializer.Deserialize(objStringsTextReader);
}
catch (Exception excep)
{
return default(T);
}
}
public static XmlElement SerializeObjectToXmlNode(object obj)
{
using (MemoryStream memoryStream = new MemoryStream())
{
try
{
XmlSerializerNamespaces xmlNameSpace = new XmlSerializerNamespaces();
xmlNameSpace.Add(string.Empty, string.Empty);
XmlWriterSettings writerSettings = new XmlWriterSettings();
writerSettings.CloseOutput = false;
writerSettings.Encoding = System.Text.Encoding.UTF8;
writerSettings.Indent = false;
writerSettings.OmitXmlDeclaration = true;
XmlWriter writer = XmlWriter.Create(memoryStream, writerSettings);
XmlSerializer xmlserializer = new XmlSerializer(obj.GetType());
xmlserializer.Serialize(writer, obj, xmlNameSpace);
writer.Close();
memoryStream.Position = 0;
XmlDocument serializeObjectDoc = new XmlDocument();
serializeObjectDoc.Load(memoryStream);
return serializeObjectDoc.DocumentElement;
}
catch (Exception excep)
{
return null;
}
}
}
}
public class StringResource
{
[XmlAttribute]
public string DELETE;
[XmlAttribute]
public string ID;
}
< STRING ID="1" DELETE="True" />
Problem is a name mismatch in your XML root node and your class
< STRING ID="1" DELETE="True" /> -- STRING here
public class StringResource -- StringResource Here.
Add xmlroot attribute to your class, and will see what happens
[XmlRoot( "STRING " )]
public class StringResource
{
[XmlAttribute]
public string DELETE;
[XmlAttribute]
public string ID;
}
Wel it's obvious Resource1.stringXml does not contain a correct XML which could be deserialized to a StringResource object. The XML should look like this:
<StringResource DELETE="CanDelete" ID="23342" />

Categories

Resources