explained.Getting exception when deserializing . Can anybody help me what has gone wrong for the reason. I have created a class for the data to be extracted from the xml file. But when deserialixing back to object I am getting exeption.
<?xml version="1.0" encoding="utf-8" ?>
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Body>
<n1:GetPlugStatusListResponse xmlns:n1="http://tempuri.org/SPSuiteWebService/StandService">
<n1:GetPlugStatusListResponse xmlns:n2="http://tempuri.org/GetPlugStatusListResponse.xsd">
<n2:StoreList>
<n2:Store>
<n2:AreaType>13</n2:AreaType>
<n2:AreaName>東京都</n2:AreaName>
<n2:StoreCd>91110002</n2:StoreCd>
</n2:Store>
<n2:Store>
</n2:Store>
...
</n2:StoreList>
public static List<Store> ParseStoreList(string fileName)
{
// Init
List<Store> listStoreList = new List<Store>();
// Parse...
using (XmlReader xmlReader = XmlReader.Create(fileName))
{
XmlSerializer EventSerializer = new XmlSerializer(typeof(Store));
while (xmlReader.ReadToFollowing("n2:Store"))
{
Store storeObject = (Store)EventSerializer.Deserialize(xmlReader.ReadSubtree());
listStoreList.Add(storeObject);
}
xmlReader.Close();
}
// Return value
return listStoreList;
}
public static List<PlugListData> ParsePlugList(string fileName)
{
// Init
List<PlugListData> listPlugList = new List<PlugListData>();
// Parse...
using (XmlReader xmlReader = XmlReader.Create(fileName))
{
XmlSerializer EventSerializer = new XmlSerializer(typeof(Store));
// Parse XML - "Event" nodes...
while (xmlReader.ReadToFollowing("n2:PlugStatus"))
{
PlugListData pluglistObject = (PlugListData)EventSerializer.Deserialize(xmlReader.ReadSubtree());
listPlugList.Add(pluglistObject);
}
// Cleanup...
xmlReader.Close();
}
// Return value
return listPlugList;
}
You could try the following
XmlSerializer deserializer = new XmlSerializer(typeof(Store));// create the serializer
TextReader reader = new StreamReader("n2:Store"); //read your text
object obj = deserializer.Deserialize(reader);// create object
Store xmlData = (Store)obj;// access data from object
Related
I am working with an XML based API that as its root node can either return a SuccessResponse or a ErrorResponse.
I am using the below to deserialize the data but I am not sure how to handle the case of the return not being a SuccessResponse.
What is the best way to handle the situation where the returned XML isn't in the expected format?
I know I could do a hack way and look for the occurrance of either SuccessResponse or ErrorResponse but that doesn't feel right.
TheIconicApiResult result = this.apiService.SendGetRequest("GetProducts", new List<AbstractParam>() { new FilterParam("live"), new LimitParam(5000) });
IXmlSerialiser xmlSerialiser = new XmlSerialiser();
var xmlBody = xmlSerialiser.ParseXML<SuccessResponse>(result.ResponseBody);
public TObject ParseXML<TObject>(string xml)
{
using (TextReader reader = new StreamReader(GetMemoryStream(xml)))
{
XmlSerializer serialiser = new XmlSerializer(typeof(TObject));
return (TObject)serialiser.Deserialize(reader);
}
}
In situations where you have an XML stream containing one of several possible document types, you can construct an XmlSerializer for each type and call XmlSerializer.CanDeserialize(XmlReader) to successively test whether the document can be deserialized into that type. This method does not advance the XmlReader past the root element so it can be called multiple times without re-reading the stream.
For instance, you could introduce the following extension method:
public static partial class XmlSerializerExtensions
{
public static object DeserializePolymorphicXml(this string xml, params Type[] types)
{
using (var textReader = new StringReader(xml))
{
return textReader.DeserializePolymorphicXml(types);
}
}
public static object DeserializePolymorphicXml(this TextReader textReader, params Type[] types)
{
if (textReader == null || types == null)
throw new ArgumentNullException();
var settings = new XmlReaderSettings { CloseInput = false }; // Let caller close the input.
using (var xmlReader = XmlReader.Create(textReader, settings))
{
foreach (var type in types)
{
var serializer = new XmlSerializer(type);
if (serializer.CanDeserialize(xmlReader))
return serializer.Deserialize(xmlReader);
}
}
throw new XmlException("Invalid root type.");
}
}
Then use it as follows:
var xmlBody = result.ResponseBody.DeserializePolymorphicXml(typeof(SuccessResponse), typeof(FailResponse));
if (xmlBody is SuccessResponse)
{
// Handle successful response
}
else if (xmlBody is FailResponse)
{
// Handle failed response
}
else
{
// unknown response
throw new InvalidOperationException("unknown response");
}
Sample fiddle.
I am working with an XML based API that as its root node can either return a SuccessResponse or a ErrorResponse.
I am using the below to deserialize the data but I am not sure how to handle the case of the return not being a SuccessResponse.
What is the best way to handle the situation where the returned XML isn't in the expected format?
I know I could do a hack way and look for the occurrance of either SuccessResponse or ErrorResponse but that doesn't feel right.
TheIconicApiResult result = this.apiService.SendGetRequest("GetProducts", new List<AbstractParam>() { new FilterParam("live"), new LimitParam(5000) });
IXmlSerialiser xmlSerialiser = new XmlSerialiser();
var xmlBody = xmlSerialiser.ParseXML<SuccessResponse>(result.ResponseBody);
public TObject ParseXML<TObject>(string xml)
{
using (TextReader reader = new StreamReader(GetMemoryStream(xml)))
{
XmlSerializer serialiser = new XmlSerializer(typeof(TObject));
return (TObject)serialiser.Deserialize(reader);
}
}
In situations where you have an XML stream containing one of several possible document types, you can construct an XmlSerializer for each type and call XmlSerializer.CanDeserialize(XmlReader) to successively test whether the document can be deserialized into that type. This method does not advance the XmlReader past the root element so it can be called multiple times without re-reading the stream.
For instance, you could introduce the following extension method:
public static partial class XmlSerializerExtensions
{
public static object DeserializePolymorphicXml(this string xml, params Type[] types)
{
using (var textReader = new StringReader(xml))
{
return textReader.DeserializePolymorphicXml(types);
}
}
public static object DeserializePolymorphicXml(this TextReader textReader, params Type[] types)
{
if (textReader == null || types == null)
throw new ArgumentNullException();
var settings = new XmlReaderSettings { CloseInput = false }; // Let caller close the input.
using (var xmlReader = XmlReader.Create(textReader, settings))
{
foreach (var type in types)
{
var serializer = new XmlSerializer(type);
if (serializer.CanDeserialize(xmlReader))
return serializer.Deserialize(xmlReader);
}
}
throw new XmlException("Invalid root type.");
}
}
Then use it as follows:
var xmlBody = result.ResponseBody.DeserializePolymorphicXml(typeof(SuccessResponse), typeof(FailResponse));
if (xmlBody is SuccessResponse)
{
// Handle successful response
}
else if (xmlBody is FailResponse)
{
// Handle failed response
}
else
{
// unknown response
throw new InvalidOperationException("unknown response");
}
Sample fiddle.
There is an error in XML document (8, 20). Inner 1: Unexpected XML declaration. The XML declaration must be the first node in the document, and no white space characters are allowed to appear before it.
OK, I understand this error.
How I get it, however, is what perplexes me.
I create the document with Microsoft's Serialize tool. Then, I turn around and attempt to read it back, again, using Microsoft's Deserialize tool.
I am not in control of writing the XML file in the correct format - that I can see.
Here is the single routine I use to read and write.
private string xmlPath = System.Web.Hosting.HostingEnvironment.MapPath(WebConfigurationManager.AppSettings["DATA_XML"]);
private object objLock = new Object();
public string ErrorMessage { get; set; }
public StoredMsgs Operation(string from, string message, FileAccess access) {
StoredMsgs list = null;
lock (objLock) {
ErrorMessage = null;
try {
if (!File.Exists(xmlPath)) {
var root = new XmlRootAttribute(rootName);
var serializer = new XmlSerializer(typeof(StoredMsgs), root);
if (String.IsNullOrEmpty(message)) {
from = "Code Window";
message = "Created File";
}
var item = new StoredMsg() {
From = from,
Date = DateTime.Now.ToString("s"),
Message = message
};
using (var stream = File.Create(xmlPath)) {
list = new StoredMsgs();
list.Add(item);
serializer.Serialize(stream, list);
}
} else {
var root = new XmlRootAttribute("MessageHistory");
var serializer = new XmlSerializer(typeof(StoredMsgs), root);
var item = new StoredMsg() {
From = from,
Date = DateTime.Now.ToString("s"),
Message = message
};
using (var stream = File.Open(xmlPath, FileMode.Open, FileAccess.ReadWrite)) {
list = (StoredMsgs)serializer.Deserialize(stream);
if ((access == FileAccess.ReadWrite) || (access == FileAccess.Write)) {
list.Add(item);
serializer.Serialize(stream, list);
}
}
}
} catch (Exception error) {
var sb = new StringBuilder();
int index = 0;
sb.AppendLine(String.Format("Top Level Error: <b>{0}</b>", error.Message));
var err = error.InnerException;
while (err != null) {
index++;
sb.AppendLine(String.Format("\tInner {0}: {1}", index, err.Message));
err = err.InnerException;
}
ErrorMessage = sb.ToString();
}
}
return list;
}
Is something wrong with my routine? If Microsoft write the file, it seems to me that it should be able to read it back.
It should be generic enough for anyone to use.
Here is my StoredMsg class:
[Serializable()]
[XmlType("StoredMessage")]
public class StoredMessage {
public StoredMessage() {
}
[XmlElement("From")]
public string From { get; set; }
[XmlElement("Date")]
public string Date { get; set; }
[XmlElement("Message")]
public string Message { get; set; }
}
[Serializable()]
[XmlRoot("MessageHistory")]
public class MessageHistory : List<StoredMessage> {
}
The file it generates doesn't look to me like it has any issues.
I saw the solution here:
Error: The XML declaration must be the first node in the document
But, in that case, it seems someone already had an XML document they wanted to read. They just had to fix it.
I have an XML document created my Microsoft, so it should be read back in by Microsoft.
The problem is that you are adding to the file. You deserialize, then re-serialize to the same stream without rewinding and resizing to zero. This gives you multiple root elements:
<?xml version="1.0"?>
<StoredMessage>
</StoredMessage
<?xml version="1.0"?>
<StoredMessage>
</StoredMessage
Multiple root elements, and multiple XML declarations, are invalid according to the XML standard, thus the .NET XML parser throws an exception in this situation by default.
For possible solutions, see XML Error: There are multiple root elements, which suggests you either:
Enclose your list of StoredMessage elements in some synthetic outer element, e.g. StoredMessageList.
This would require you to load the list of messages from the file, add the new message, and then truncate the file and re-serialize the entire list when adding a single item. Thus the performance may be worse than in your current approach, but the XML will be valid.
When deserializing a file containing concatenated root elements, create an XML writer using XmlReaderSettings.ConformanceLevel = ConformanceLevel.Fragment and iteratively walk through the concatenated root node(s) and deserialize each one individually as shown, e.g., here. Using ConformanceLevel.Fragment allows the reader to parse streams with multiple root elements (although multiple XML declarations will still cause an error to be thrown).
Later, when adding a new element to the end of the file using XmlSerializer, seek to the end of the file and serialize using an XML writer returned from XmlWriter.Create(TextWriter, XmlWriterSettings)
with XmlWriterSettings.OmitXmlDeclaration = true. This prevents output of multiple XML declarations as explained here.
For option #2, your Operation would look something like the following:
private string xmlPath = System.Web.Hosting.HostingEnvironment.MapPath(WebConfigurationManager.AppSettings["DATA_XML"]);
private object objLock = new Object();
public string ErrorMessage { get; set; }
const string rootName = "MessageHistory";
static readonly XmlSerializer serializer = new XmlSerializer(typeof(StoredMessage), new XmlRootAttribute(rootName));
public MessageHistory Operation(string from, string message, FileAccess access)
{
var list = new MessageHistory();
lock (objLock)
{
ErrorMessage = null;
try
{
using (var file = File.Open(xmlPath, FileMode.OpenOrCreate))
{
list.AddRange(XmlSerializerHelper.ReadObjects<StoredMessage>(file, false, serializer));
if (list.Count == 0 && String.IsNullOrEmpty(message))
{
from = "Code Window";
message = "Created File";
}
var item = new StoredMessage()
{
From = from,
Date = DateTime.Now.ToString("s"),
Message = message
};
if ((access == FileAccess.ReadWrite) || (access == FileAccess.Write))
{
file.Seek(0, SeekOrigin.End);
var writerSettings = new XmlWriterSettings
{
OmitXmlDeclaration = true,
Indent = true, // Optional; remove if compact XML is desired.
};
using (var textWriter = new StreamWriter(file))
{
if (list.Count > 0)
textWriter.WriteLine();
using (var xmlWriter = XmlWriter.Create(textWriter, writerSettings))
{
serializer.Serialize(xmlWriter, item);
}
}
}
list.Add(item);
}
}
catch (Exception error)
{
var sb = new StringBuilder();
int index = 0;
sb.AppendLine(String.Format("Top Level Error: <b>{0}</b>", error.Message));
var err = error.InnerException;
while (err != null)
{
index++;
sb.AppendLine(String.Format("\tInner {0}: {1}", index, err.Message));
err = err.InnerException;
}
ErrorMessage = sb.ToString();
}
}
return list;
}
Using the following extension method adapted from Read nodes of a xml file in C#:
public partial class XmlSerializerHelper
{
public static List<T> ReadObjects<T>(Stream stream, bool closeInput = true, XmlSerializer serializer = null)
{
var list = new List<T>();
serializer = serializer ?? new XmlSerializer(typeof(T));
var settings = new XmlReaderSettings
{
ConformanceLevel = ConformanceLevel.Fragment,
CloseInput = closeInput,
};
using (var xmlTextReader = XmlReader.Create(stream, settings))
{
while (xmlTextReader.Read())
{ // Skip whitespace
if (xmlTextReader.NodeType == XmlNodeType.Element)
{
using (var subReader = xmlTextReader.ReadSubtree())
{
var logEvent = (T)serializer.Deserialize(subReader);
list.Add(logEvent);
}
}
}
}
return list;
}
}
Note that if you are going to create an XmlSerializer using a custom XmlRootAttribute, you must cache the serializer to avoid a memory leak.
Sample fiddle.
I am loading MusicXML-files into my program. The problem: There are two “dialects”, timewise and partwise, which have different root-nodes (and a different structure):
<?xml version="1.0" encoding='UTF-8' standalone='no' ?>
<!DOCTYPE score-partwise PUBLIC "-//Recordare//DTD MusicXML 2.0 Partwise//EN" "http://www.musicxml.org/dtds/partwise.dtd">
<score-partwise version="2.0">
<work>...</work>
...
</score-partwise>
and
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE score-timewise PUBLIC "-//Recordare//DTD MusicXML 2.0 Timewise//EN" "http://www.musicxml.org/dtds/timewise.dtd">
<score-timewise version="2.0">
<work>...</work>
...
</score-timewise>
My code for deserializing the partwise score so far is:
using (var fileStream = new FileStream(openFileDialog.FileName, FileMode.Open))
{
var xmlSerializer = new XmlSerializer(typeof(ScorePartwise));
var result = (ScorePartwise)xmlSerializer.Deserialize(fileStream);
}
What would be the best way to differentiate between the two dialects?
Here's a way to do it by using an XDocument to parse the file, read the root element to determine the type, and read it into your serializer.
var xdoc = XDocument.Load(filePath);
Type type;
if (xdoc.Root.Name.LocalName == "score-partwise")
type = typeof(ScorePartwise);
else if (xdoc.Root.Name.LocalName == "score-timewise")
type = typeof(ScoreTimewise);
else
throw new Exception();
var xmlSerializer = new XmlSerializer(type);
var result = xmlSerializer.Deserialize(xdoc.CreateReader());
I would create both serializers
var partwiseSerializer = new XmlSerializer(typeof(ScorePartwise));
var timewiseSerializer = new XmlSerializer(typeof(ScoreTimewise));
Assuming that there is only these two I would call CanDeserialize method on one
using (var fileStream = new FileStream(openFileDialog.FileName, FileMode.Open))
{
using (var xmlReader = XmlReader.Create(filStream))
{
if (partwiseSerializer.CanDeserialize(xmlReader))
{
var result = partwiseSerializer.Deserialize(xmlReader);
}
else
{
var result = timewiseSerializer.Deserialize(xmlReader);
}
}
}
Obviously this is just an idea how to do it. If there were more options or according to your application design I would use a more sophisticated way to call CanDeserialize, but that method is the key in my opinion:
http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.candeserialize.aspx
The XmlReader class can be found here:
http://msdn.microsoft.com/en-us/library/System.Xml.XmlReader(v=vs.110).aspx
If you're concerned about resource usage:
internal const string NodeStart = "<Error ";
public static bool IsErrorDocument(string xml)
{
int headerLen = 1;
if (xml.StartsWith(Constants.XMLHEADER_UTF8))
{
headerLen += Constants.XMLHEADER_UTF8.Length;
}
else if (xml.StartsWith(Constants.XMLHEADER_UTF16))
{
headerLen += Constants.XMLHEADER_UTF16.Length;
}
else
{
return false;
}
if (xml.Length < headerLen + NodeStart.Length)
{
return false;
}
return xml.Substring(headerLen, NodeStart.Length) == NodeStart;
}
internal class Constants
{
public const string XMLHEADER_UTF16 = "<?xml version=\"1.0\" encoding=\"utf-16\"?>";
public const string XMLHEADER_UTF8 = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
}
I have one problem. I have to serialize an object and that sam object is converted to XML, but it's a datetime object.
Ok, i have string variable which is filled with data from some sql query, like this
//DateDeliveryRequest
if (rw_mat["dat_pot"].ToString().Length <= 0)
{
date_req = "";
}
else
{
date_req = rw_mat["dat_pot"].ToString();
}
Now, date_req is being passet to object like this:
var dtfi = new DateTimeFormatInfo { ShortDatePattern = "dd-MM-yyyy", DateSeparator = "-" };
Agr3PL.DataArea.Header.DateDeliveryRequest = Convert.ToDateTime(date_req, dtfi);
And at the end this object with among other is being passed to serialize function:
private string SerializeAnObject(object obj)
{
System.Xml.XmlDocument doc = new XmlDocument();
System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(obj.GetType());
System.IO.MemoryStream stream = new System.IO.MemoryStream();
try
{
serializer.Serialize(stream, obj);
stream.Position = 0;
doc.Load(stream);
return doc.InnerXml;
}
catch (Exception ex)
{
WriteErrors.WriteToLogFile("WS.SAVE_DOK_SERIJALIZACIJA", ex.ToString());
throw ex;
}
So i want to get datetime variable to xml but I don't, the xml has to look something like this(It is just a segment)
- <Header>
<MessageType>COR</MessageType>
<UniqueHeaderNumber />
<UniqueHeaderNumberFromWMS />
<CompanyCode />
<OrderNumber />
<InvoiceNumber />
<MovementNumber />
<ReceiptNumber />
<DebitNoteNumber />
<PickNoteNumber />
<LoadNumber />
<DropSequence />
<BulkPickNoteNumber />
<NumberOfPallets />
<DateDeliveryRequest />
But the problem is that the xml is not showing the node >DateDeliveryRequest it's not there
I don't get error just there is no node >DateDeliveryRequest???
I don't know is it the problem in serializer function or on something else, maybe in formating date or something else?
I tested this code:
public class Test
{
private DateTime dateDeliveryRequestField;
[System.Xml.Serialization.XmlElementAttribute(DataType = "date")]
public System.DateTime DateDeliveryRequest { get { return this.dateDeliveryRequestField; } set { this.dateDeliveryRequestField = value; } }
}
private string SerializeAnObject(object obj)
{
System.Xml.XmlDocument doc = new XmlDocument();
System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(obj.GetType());
System.IO.MemoryStream stream = new System.IO.MemoryStream();
try
{
serializer.Serialize(stream, obj);
stream.Position = 0;
doc.Load(stream);
return doc.InnerXml;
}
catch (Exception ex)
{
throw ex;
}
}
Test n = new Test();
n.DateDeliveryRequest = DateTime.Parse("2012-10-07");
string result = SerializeAnObject(n);
and result:
<?xml version="1.0"?>
<Test xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<DateDeliveryRequest>2012-10-07</DateDeliveryRequest>
</Test>
So everything looks good.
To serialize dates use this string format
date_req = rw_mat["dat_pot"].ToString("s");