问题
I have an xml document, where i serialize data dinamically, appending new data if i have a new request. The object properties i serialize are like this
[XmlRoot("LogRecords")]
public class LogRecord
{
public string Message { get; set; }
public DateTime SendTime { get; set; }
public string Sender { get; set; }
public string Recipient { get; set; }
}
Serializing is done in this way :
var stringwriter = new StringWriter();
var serializer = new XmlSerializer(object.GetType());
serializer.Serialize(stringwriter, object);
var smsxmlStr = stringwriter.ToString();
var smsRecordDoc = new XmlDocument();
smsRecordDoc.LoadXml(smsxmlStr);
var smsElement = smsRecordDoc.DocumentElement;
var smsLogFile = new XmlDocument();
smsLogFile.Load("LogRecords.xml");
var serialize = smsLogFile.CreateElement("LogRecord");
serialize.InnerXml = smsElement.InnerXml;
smsLogFile.DocumentElement.AppendChild(serialize);
smsLogFile.Save("LogRecords.xml");
While serializing i use LogFile.CreateElement("LogRecord") and my xml file looks like this :
<LogRecords>
<LogRecord>
<Message>Some messagge</Message>
<SendTime>2017-12-13T22:04:40.1109661+01:00</SendTime>
<Sender>Sender</Sender>
<Recipient>Name</Recipient>
</LogRecord>
<LogRecord>
<Message>Some message too</Message>
<SendTime>2017-12-13T22:05:08.5720173+01:00</SendTime>
<Sender>sender</Sender>
<Recipient>name</Recipient>
</LogRecord>
</LogRecords>
When i try to deserialize like this
XmlSerializer deserializer = new XmlSerializer(typeof(LogRecord));
TextReader reader = new StreamReader("LogRecords.xml");
object obj = deserializer.Deserialize(reader);
LogRecord records = (LogRecord)obj;
reader.Close();
I get null value for each property Message, Sender Recipient and a random value for SendTime, and i know it's because it doesn't recognise the XmlElement LogRecord i added while serializing..
Is there any way to read this xml element so i can take the right property values?
Ps. Sorry if i have messed up the variables, i tried to simplify the code when i added it here and i may have mixed some variables..
Thank you in advance.
回答1:
You could try to generate POCO classes from XML in Visual Studio as it's described here.
You could serialize/deserialize those POCOs using with simple util methods like:
public static T DeserializeXML<T>(string content) { if (content == null) return default(T); XmlSerializer xs = new XmlSerializer(typeof(T)); byte[] byteArray = Encoding.ASCII.GetBytes(content); var contentStream = new MemoryStream(byteArray); var xml = xs.Deserialize(contentStream); return (T)xml; } public static string SerializeAsXML(object item) { if (item == null) return null; XmlSerializer xs = new XmlSerializer(item.GetType()); using (var sw = new StringWriter()) { using (XmlWriter writer = XmlWriter.Create(sw, new XmlWriterSettings { Indent = true })) { xs.Serialize(writer, item); return sw.ToString(); } } }LogRecords probably should be a collection (e.g. an array in this POCO):
/// <remarks/> [System.SerializableAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] [System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)] public partial class Log { /// <remarks/> [System.Xml.Serialization.XmlArrayAttribute("LogRecords")] [System.Xml.Serialization.XmlArrayItemAttribute("LogRecord", IsNullable = false)] public LogRecord[] LogRecords { get; set; } }
for the next XML format:
<Log>
<LogRecords>
<LogRecord>
<Message>Some messagge</Message>
<SendTime>2017-12-13T22:04:40.1109661+01:00</SendTime>
<Sender>Sender</Sender>
<Recipient>Name</Recipient>
</LogRecord>
<LogRecord>
<Message>Some message too</Message>
<SendTime>2017-12-13T22:05:08.5720173+01:00</SendTime>
<Sender>sender</Sender>
<Recipient>name</Recipient>
</LogRecord>
</LogRecords>
</Log>
回答2:
You manually add the root element in the xml. Therefore, you must also manually skip it when reading.
XmlSerializer deserializer = new XmlSerializer(typeof(LogRecord));
using (var xmlReader = XmlReader.Create("LogRecords.xml"))
{
// Skip root element
xmlReader.ReadToFollowing("LogRecord");
LogRecord record = (LogRecord)deserializer.Deserialize(xmlReader);
}
Remove the [XmlRoot("LogRecords")] attribute to make it work.
Of course, you will always get the first element in the xml.
As already suggested in the comments, use the list.
List<LogRecord> logRecords = new List<LogRecord>();
var logRecord = new LogRecord { ... };
// Store each new logRecord to list
logRecords.Add(logRecord);
var serializer = new XmlSerializer(typeof(List<LogRecord>));
// Serialization is done with just a couple lines of code.
using (var fileStream = new FileStream("LogRecords.xml", FileMode.Create))
{
serializer.Serialize(fileStream, logRecords);
}
// As well as deserialization
using (var fileStream = new FileStream("LogRecords.xml", FileMode.Open))
{
logRecords = (List<LogRecord>)serializer.Deserialize(fileStream);
}
Thus become unnecessary manipulation using XmlDocument and fuss with manually adding-skipping the root node.
来源:https://stackoverflow.com/questions/47814724/read-xml-element-while-deserializing-c-sharp