以特定格式.net将DateTime序列化为XML
本文关键字:DateTime 序列化 XML net 定格 格式 | 更新日期: 2023-09-27 18:00:09
我收集了大量自动生成的类,这些类使用.NET XmlSerializer序列化到XML/从XML反序列化。其中一些类包含DateTime属性。
我需要使用特定格式序列化所有DateTime属性,例如"u"。:
System.DateTime.Now.ToString("u");
//returns something like "2008-06-15 21:15:07Z"
反序列化方法似乎可以使用这种格式,但序列化不行-它只是给我提供了与主机系统中默认格式相同的硬编码格式(也许我可以通过更改线程设置来欺骗序列化程序?)(检查Update#1)。
注意:我已经检查了一些相关的问题,它们通过修改原始属性和添加新属性来解决。对我来说,这是不可接受的,因为我必须做大量的修改。
- 如何在C中仅从DateTime序列化Xml日期#
- 强制XmlSerializer将DateTime序列化为';YYYY-MM-DD hh:MM:ss'
下面是我用来测试这个问题的一个示例测试类。
using System;
using System.Linq;
using System.Text;
using System.Xml;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Xml.Linq;
using System.Xml.Serialization;
using System.Globalization;
using System.IO;
namespace FunkyTests
{
[TestClass]
public class SerializationTests
{
[TestMethod]
public void FunkySerializationTest()
{
var date = DateTime.Now;
var dummy = new Dummy() { DummyProperty = date };
var xml = SerializeToXml(dummy);//serializes with "o" format
var expected = date.ToString("u", new CultureInfo("en-US"));//in this example I want "u" format
var actual = XDocument.Parse(xml).Descendants("DummyProperty").Single().Value;
Assert.AreEqual(expected, actual);
}
[TestMethod]
public void FunkyDeserializationTest()
{
var date = DateTime.Now;
var dummy = new Dummy() { DummyProperty = date };
var xml = SerializeToXml(dummy);//serializes with "o" format
var deserializedDummy = DeserializeFromXml<Dummy>(xml);
Assert.AreEqual(dummy.DummyProperty, deserializedDummy.DummyProperty);
}
private static T DeserializeFromXml<T>(string xml)
{
using (var textReader = new StringReader(xml))
{
using (var reader = XmlReader.Create(textReader))
{
var serializer = new XmlSerializer(typeof(T));
var result = serializer.Deserialize(reader);
return (T)result;
}
}
}
private static string SerializeToXml<T>(T objectToSerialize)
{
var xml = new StringBuilder();
using (var writer = XmlWriter.Create(xml, new XmlWriterSettings { OmitXmlDeclaration = true }))
{
var ns = new XmlSerializerNamespaces();
ns.Add(string.Empty, string.Empty);
var serializer = new XmlSerializer(typeof(T));
serializer.Serialize(writer, objectToSerialize, ns);
}
return xml.ToString();
}
public class Dummy
{
public DateTime DummyProperty { get; set; }
}
}
}
有什么新奇的想法吗?
更新#1:我认为日期序列化依赖于Thread.CurrentCulture。如果我正确解释XmlSerializer代码,则格式是硬编码的(谢谢ILSpy)。
// System.Xml.Serialization.XmlCustomFormatter
internal static string FromDateTime(DateTime value)
{
if (XmlCustomFormatter.Mode == DateTimeSerializationSection.DateTimeSerializationMode.Local)
{
return XmlConvert.ToString(value, "yyyy-MM-ddTHH:mm:ss.fffffffzzzzzz");
}
return XmlConvert.ToString(value, XmlDateTimeSerializationMode.RoundtripKind);
}
更新#2:我添加了一种测试方法,该方法使用Alexander Petrov提出的答案。它在断言Ticks时失败。根据Serialize DateTime的说法,二进制问题存在于DateTime的内部,是由失去DateTime的"Kind"引起的。有人建议使用DateTimeOffset,这会导致序列化的另一个问题,如How can I XML Serialize a DateTimeOffset Property?
尝试使用自定义xml读写器。
public class CustomDateTimeWriter : XmlTextWriter
{
public CustomDateTimeWriter(TextWriter writer) : base(writer) { }
public CustomDateTimeWriter(Stream stream, Encoding encoding) : base(stream, encoding) { }
public CustomDateTimeWriter(string filename, Encoding encoding) : base(filename, encoding) { }
public override void WriteRaw(string data)
{
DateTime dt;
if (DateTime.TryParse(data, out dt))
base.WriteRaw(dt.ToString("u", new CultureInfo("en-US")));
else
base.WriteRaw(data);
}
}
public class CustomDateTimeReader : XmlTextReader
{
public CustomDateTimeReader(TextReader input) : base(input) { }
// define other required constructors
public override string ReadElementString()
{
string data = base.ReadElementString();
DateTime dt;
if (DateTime.TryParse(data, null, DateTimeStyles.AdjustToUniversal, out dt))
return dt.ToString("o");
else
return data;
}
}
使用
var dummy = new Dummy { DummyProperty = DateTime.Now };
Console.WriteLine(dummy.DummyProperty);
var xs = new XmlSerializer(typeof(Dummy));
string xml;
using (var stringWriter = new StringWriter())
using (var xmlWriter = new CustomDateTimeWriter(stringWriter))
{
xmlWriter.Formatting = Formatting.Indented;
xs.Serialize(xmlWriter, dummy);
xml = stringWriter.ToString();
}
Console.WriteLine(xml);
using (var stringReader = new StringReader(xml))
using (var xmlReader = new CustomDateTimeReader(stringReader))
{
dummy = (Dummy)xs.Deserialize(xmlReader);
Console.WriteLine(dummy.DummyProperty);
}
优点:
这种方法自动(反)序列化日期-时间的所有值到/从所需格式,而不需要更改生成的类。
缺点:
这种方法可能会意外地更改日期时间等值。
这种方法可能会减慢(反)序列化的速度。