I am trying to serialize a class in c# but the output is not quite I am after. I want to get rid of one element in output xml - class name - that comes along with serialization.
My class is:
[XmlType("ADSobjotsing")]
public class ObjKompParam
{
[XmlElement("aadressTekst")]
public string Tekst;
[XmlElement("adsOid")]
public string OID;
My code is:
protected override XElement ComposeQueryBody(object InputParams)
{
ObjKompParam param = (ObjKompParam)InputParams;
var ads_o_q = new ObjKompParam();
XElement body = new XElement(SOAPNS + "Body",
new XElement(prod + "ADSobjotsing"));
var ns = new XmlSerializerNamespaces();
ns.Add("", "");
XmlSerializer serializer = new XmlSerializer(typeof(ObjKompParam),"");
XElement xe;
using (var stream = new MemoryStream())
{
serializer.Serialize(stream, param, ns);
stream.Position = 0;
using (XmlReader reader = XmlReader.Create(stream))
{
xe = XElement.Load(reader);
}
}
body.Descendants(prod + "ADSobjotsing").First().Add(new XElement(xe));
return body;
}
The output I get is:
<SOAP-ENV:Body>
<prod:ADSobjotsing>
<ADSobjotsing>
<aadressTekst>Sügise 10</aadressTekst>
</ADSobjotsing>
</prod:ADSobjotsing>
</SOAP-ENV:Body>
The xml output (body) I am after is following:
<SOAP-ENV:Body>
<prod:ADSobjotsing>
<aadressTekst>Sügise 10</aadressTekst>
</prod:ADSobjotsing>
</SOAP-ENV:Body>
I answer myself, as I worked out the solution:
XmlSerializer serializer = new XmlSerializer(typeof(ObjKompParam),"");
XElement xe;
using (var stream = new MemoryStream()) //write into stream
{
serializer.Serialize(stream, param, ns); //writer, object
stream.Position = 0;
using (XmlReader reader = XmlReader.Create(stream))
{
xe = XElement.Load(reader);
}
}
var child = xe.Descendants();
body.Descendants(prod + "ADSobjotsing").First().Add(child);
return body;
I made the new variable for object class ObjKompParam children and added children as descendants.
Related
I have Converted a the Different entities in a List and now I have a master list containing the many list of different models.
public static string xmlSerialize(List<Object> o)
{
XmlDocument xmlOut = new XmlDocument();
foreach(var i in o)
{
using (MemoryStream xmlStream = new MemoryStream())
{
//MemoryStream myMemStr = new MemoryStream();
XmlSerializer xmlSerializer = new XmlSerializer(i.GetType());
xmlSerializer.Serialize(xmlStream, i);
xmlStream.Position = 0;
xmlOut.Load(xmlStream);
}
}
return xmlOut.InnerXml;
}
The above method converts the multiple List into a XML. But this code Overwrites the previous XML string in every loop run.
Is There any solution to get the single XML for every entity.
IMHO - the simplest solution here is to load xml into temporary XmlDocument and then perform Import
Idea is the following
public static string xmlSerialize(List<Object> o)
{
XmlDocument xmlOut = new XmlDocument();
foreach(var i in o)
{
var tmpDoc = new XmlDocument();
using (MemoryStream xmlStream = new MemoryStream())
{
//MemoryStream myMemStr = new MemoryStream();
XmlSerializer xmlSerializer = new XmlSerializer(i.GetType());
xmlSerializer.Serialize(xmlStream, i);
xmlStream.Position = 0;
tmpDoc.Load(xmlStream);
}
var newNode = xmlOut.ImportNode(tmpDoc.DocumentElement.LastChild, true);
xmlOut.DocumentElement.AppendChild(newNode);
}
return xmlOut.InnerXml;
}
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 need to set the OmitXmlDeclaration property of the XmlWriterSettings for a XmlWriter to false to not have XML declarations created. The issue is that I have created the XmlWriter from a call of a XPathNavigator.AppendChild() method. Code below:
public String GetEntityXml<T>(List<T> entities)
{
XmlDocument xmlDoc = new XmlDocument();
XPathNavigator nav = xmlDoc.CreateNavigator();
using (XmlWriter writer = nav.AppendChild())
{
XmlSerializer ser = new XmlSerializer(typeof(List<T>), new XmlRootAttribute(typeof(T).Name + "_LIST"));
ser.Serialize(writer, entities);
}
StringWriter stringWriter = new StringWriter();
XmlTextWriter xmlTextWriter = new XmlTextWriter(stringWriter);
xmlDoc.WriteTo(xmlTextWriter);
string resultString = stringWriter.ToString();
stringWriter.Close();
xmlTextWriter.Close();
return resultString;
}
Any idea how to serialize the List and not have XML declarations?
I’m not getting the XML declaration when I execute your code. Serializing a List<int> gives me:
<Int32_LIST xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<int>5</int>
<int>7</int>
<int>2</int>
</Int32_LIST>
Note that the “XML declaration” that OmitXmlDeclaration refers to is typically something similar to:
<?xml version="1.0" encoding="UTF-8" ?>
If you’re instead referring to the xmlns parts, then those are called “XML namespace declarations”, and may be eliminated by initializing an XmlSerializerNamespaces instance with a default empty namespace, and passing it to your Serialize method:
XmlSerializer ser = new XmlSerializer(typeof(List<T>), new XmlRootAttribute(typeof(T).Name + "_LIST"));
var namespaces = new XmlSerializerNamespaces(new[] { new XmlQualifiedName("", "") });
ser.Serialize(writer, entities, namespaces);
The below is a shortened implementation which achieves the same result as your code:
public String GetEntityXml<T>(List<T> entities)
{
var sb = new StringBuilder();
var settings = new XmlWriterSettings { OmitXmlDeclaration = true };
using (XmlWriter writer = XmlWriter.Create(sb, settings))
{
XmlSerializer ser = new XmlSerializer(typeof(List<T>), new XmlRootAttribute(typeof(T).Name + "_LIST"));
var namespaces = new XmlSerializerNamespaces(new[] { new XmlQualifiedName("", "") });
ser.Serialize(writer, entities, namespaces);
}
return sb.ToString();
}
Try this approach (switched to var for readability):
public String GetEntityXml<T>(List<T> entities)
{
var xmlDoc = new XmlDocument();
var nav = xmlDoc.CreateNavigator();
using (var sw = new StringWriter())
{
//Create an XmlWriter that will omit xml declarations
var s = new XmlWriterSettings{ OmitXmlDeclaration = true };
using (var xmlWriter = XmlWriter.Create(sw, s))
{
//Use the following to serialize without namespaces
var ns = new XmlSerializerNamespaces();
ns.Add("", "");
var ser = new XmlSerializer(typeof(List<T>),
new XmlRootAttribute(typeof(T).Name + "_LIST"));
ser.Serialize(xmlWriter, entities, ns);
}
//Pass xml string to nav.AppendChild()
nav.AppendChild(sw.ToString());
}
using (var stringWriter = new StringWriter())
{
using (var xmlTextWriter = XmlWriter.Create(stringWriter))
{
xmlDoc.WriteTo(xmlTextWriter);
}
return stringWriter.ToString();
}
}
Rather than using nav.AppendChild() to create the XmlWriter, you can create the XmlWriter separately and then just use nav.AppendChild(string) to write the XML into xmlDoc. When you create the XmlWriter yourself, you can omit the XML declaration. Also, when you serialize, you'll probably want to omit the xmlns:xsi and xmlns:xsd namespaces using the XmlSerializerNamespaces class.
In order to return useful information in SoapException.Detail for an asmx web service, I took an idea from WCF and created a fault class to contain said useful information. That fault object is then serialised to the required XmlNode of a thrown SoapException.
I'm wondering whether I have the best code to create the XmlDocument - here is my take on it:
var xmlDocument = new XmlDocument();
var serializer = new XmlSerializer(typeof(T));
using (var stream = new MemoryStream())
{
serializer.Serialize(stream, theObjectContainingUsefulInformation);
stream.Flush();
stream.Seek(0, SeekOrigin.Begin);
xmlDocument.Load(stream);
}
Is there a better way of doing this?
UPDATE: I actually ended up doing the following, because unless you wrap the XML in a <detail> xml element, you get a SoapHeaderException at the client end:
var serialiseToDocument = new XmlDocument();
var serializer = new XmlSerializer(typeof(T));
using (var stream = new MemoryStream())
{
serializer.Serialize(stream, e.ExceptionContext);
stream.Flush();
stream.Seek(0, SeekOrigin.Begin);
serialiseToDocument.Load(stream);
}
// Remove the xml declaration
serialiseToDocument.RemoveChild(serialiseToDocument.FirstChild);
// Memorise the node we want
var serialisedNode = serialiseToDocument.FirstChild;
// and wrap it in a <detail> element
var rootNode = serialiseToDocument.CreateNode(XmlNodeType.Element, "detail", "");
rootNode.AppendChild(serialisedNode);
UPDATE 2: Given John Saunders excellent answer, I've now started using the following:
private static void SerialiseFaultDetail()
{
var fault = new ServiceFault
{
Message = "Exception occurred",
ErrorCode = 1010
};
// Serialise to the XML document
var detailDocument = new XmlDocument();
var nav = detailDocument.CreateNavigator();
if (nav != null)
{
using (XmlWriter writer = nav.AppendChild())
{
var ser = new XmlSerializer(fault.GetType());
ser.Serialize(writer, fault);
}
}
// Memorise and remove the element we want
XmlNode infoNode = detailDocument.FirstChild;
detailDocument.RemoveChild(infoNode);
// Move into a root <detail> element
var rootNode = detailDocument.AppendChild(detailDocument.CreateNode(XmlNodeType.Element, "detail", ""));
rootNode.AppendChild(infoNode);
Console.WriteLine(detailDocument.OuterXml);
Console.ReadKey();
}
EDIT: Creates output inside of detail element
public class MyFault
{
public int ErrorCode { get; set; }
public string ErrorMessage { get; set; }
}
public static XmlDocument SerializeFault()
{
var fault = new MyFault
{
ErrorCode = 1,
ErrorMessage = "This is an error"
};
var faultDocument = new XmlDocument();
var nav = faultDocument.CreateNavigator();
using (var writer = nav.AppendChild())
{
var ser = new XmlSerializer(fault.GetType());
ser.Serialize(writer, fault);
}
var detailDocument = new XmlDocument();
var detailElement = detailDocument.CreateElement(
"exc",
SoapException.DetailElementName.Name,
SoapException.DetailElementName.Namespace);
detailDocument.AppendChild(detailElement);
detailElement.AppendChild(
detailDocument.ImportNode(
faultDocument.DocumentElement, true));
return detailDocument;
}
I have a xNode made by JSON.
C# code:
Class class = new Class();
class.ComboBoxChecked = Class.ComboBoxChecked;
class.RadioButtonChecked = Class.RadioButtonChecked;
string test = JsonConvert.SerializeObject(class);
XNode node = JsonConvert.DeserializeXNode(test, "Root");
XML:
<Root>
<RadioButtonChecked>1</RadioButtonChecked>
<ComboBoxChecked>5</ComboBoxChecked>
</Root>
My goal is to add a Namespace to it.
How can i achieve this?
You can add namespaces at root level this way:
XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("example", "http://www.w3.org");
using (var ms = new MemoryStream())
{
using (TextWriter writer = new StreamWriter(ms))
{
var xmlSerializer = new XmlSerializer(typeof(MyClass));
xmlSerializer.Serialize(writer, myClassInstance, ns);
XNode node = XElement.Parse(Encoding.ASCII.GetString(ms.ToArray()));
}
}
If you need namespaces in it's children, you can edit your class using the IXmlSerializable interface, here's an Example