【问题标题】:Serialize compact XML序列化紧凑的 XML
【发布时间】:2023-03-28 11:47:01
【问题描述】:

我有一个包含四个字段(日期时间、枚举、字符串、字符串)的类。我想以紧凑的方式将它与一个 XML 元素或一系列 XML 元素进行序列化。例如,我可能会将其序列化为这样的:

<i t='234233' a='3'><u>Username1</u><s1>This is a string</s1></i>
<i t='234233' a='4'><u>Username2</u><s1>This is a string</s1></i>
<i t='223411' a='1'><u>Username3</u><s1>This is a string</s1></i>

其中“i”是每个类实例,“t”是日期时间刻度,“a”是枚举值,元素是字符串。

我希望没有根元素,但如果有的话,我希望它尽可能小。

我尝试将 XmlSerializer 与 XmlWriterSettings 类一起使用,但我无法摆脱命名空间和根元素。

这样做的最佳方法是什么?我没有保存到文件,我正在读取和写入内存中的字符串。

【问题讨论】:

  • XML 需要一个根元素才能形成良好的格式;因此大多数工具都不会产生一个。
  • 序列化这些对象究竟是为了什么目的?这可能会帮助我们帮助您。
  • 您使用的是什么版本的 .NET?可能您可以使用 DataContractSerializer,它可以序列化为 XML 的紧凑二进制形式。
  • 使用 .NET 2.0。我正在压缩通过 TCP/IP 和数据库存储进行传输。人类可读优于二进制,但越短越好。

标签: c# xml xml-serialization


【解决方案1】:

System.Xml.Linq

XElement xElem = new XElement("r");
for (int i = 0; i < 3; i++)
{
    xElem.Add(
        new XElement("i",
                new XAttribute("t", "234233"),
                new XAttribute("a", "3"),
                new XElement("u", "UserName"),
                new XElement("s1", "This is a string")
        )
    );
}
var str = xElem.ToString();

阅读

XElement xElem2 = XElement.Load(new StringReader(str));
foreach(var item in xElem2.Descendants("i"))
{
    Console.WriteLine(item.Attribute("t").Value + " " + item.Element("u").Value);
}

PS:

您无需将xElem 转换为字符串即可在内存中使用该xml

【讨论】:

    【解决方案2】:

    如果你的数据这么简单,可以直接使用XmlWriter:

    class Data {
        public DateTime Date { get; set; }
        public int Code { get; set; }
        public string First { get; set; }
        public string Last { get; set; }
    }
    
    static void Main() {
        var sb = new StringBuilder();
        var xws = new XmlWriterSettings();
        xws.OmitXmlDeclaration = true;
        xws.Indent = false;
        var elements = new[] {
            new Data { Date = DateTime.Now, First = "Hello", Last = "World", Code = 2}
        ,   new Data { Date = DateTime.UtcNow, First = "Quick", Last = "Brown", Code = 4}
        };
        using (var xw = XmlWriter.Create(sb, xws)) {
            xw.WriteStartElement("root");
            foreach (var d in elements) {
                xw.WriteStartElement("i");
                xw.WriteAttributeString("t", ""+d.Date);
                xw.WriteAttributeString("a", "" + d.Code);
                xw.WriteElementString("u", d.First);
                xw.WriteElementString("s1", d.Last);
                xw.WriteEndElement();
            }
            xw.WriteEndElement();
        }
        Console.WriteLine(sb.ToString());
    }
    

    运行这个程序会产生以下输出(为了清楚起见,我添加了换行符;它们在输出中不是):

    <root>
    <i t="2/9/2012 3:16:56 PM" a="2"><u>Hello</u><s1>World</s1></i>
    <i t="2/9/2012 8:16:56 PM" a="4"><u>Quick</u><s1>Brown</s1></i>
    </root>
    

    如果您想回读信息,则需要该根元素。最方便的方法是使用LINQ2XML:

    var xdoc = XDocument.Load(new StringReader(xml));
    var back = xdoc.Element("root").Elements("i").Select(
        e => new Data {
            Date = DateTime.Parse(e.Attribute("t").Value)
        ,   Code = int.Parse(e.Attribute("a").Value)
        ,   First = e.Element("u").Value
        ,   Last = e.Element("s1").Value
        }
    ).ToList();
    

    【讨论】:

    • 这为我编写紧凑的字符串做得很好。我假设 XmlReader.Create 以类似的方式将其读回课堂?
    • @Moozhe 我添加了一个如何使用 LINQ2XML 读回它的示例。
    • 实际上没有使用 Linq,因为它是 .NET 2.0。我正在努力让 XmlReader 工作并检查空字符串或垃圾字符串的错误。
    【解决方案3】:

    我个人只使用StringBuilder。

    如果大小是您的第一大顾虑,请考虑使用 json 或 yaml 而不是 XML。

    【讨论】:

    • 我主要关心的是读取信息的最佳方式。字符串阅读器? xml阅读器? xml节点列表?实施才是真正的问题。
    • 你会使用StringBuilder来形成一个xml吗?
    • 一般?不。要写一些没有根的东西(即无效的 XML)?大概吧。
    【解决方案4】:

    我相信,您需要实现自己的序列化程序,这会很痛苦。那,或者您可以在序列化后手动删除不需要的内容,这可能会起作用。

    如果您关心大小,您应该使用BinaryFormatter 序列化为二进制文件。如果您需要将其存储为字符串,则始终可以对其进行 base-64 编码。 (BinaryFormatter 的工作方式几乎与 XmlSerializer 一样,除了输出是原始二进制文件,而不是格式良好的 XML。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-03-15
      • 2010-10-07
      • 1970-01-01
      • 2010-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多