C# Xml序列化、集合和根元素

标签 c# xml serialization collections root-node

我的应用序列化流中的对象。 这是我需要的示例:

<links>
  <link href="/users" rel="users" />
  <link href="/features" rel="features" />
</links>

在这种情况下,该对象是“链接”对象的集合。

------------第一个版本

起初我使用了DataContractSerializer,但是你不能将成员序列化为属性(source)

这是对象:

[DataContract(Name="link")]
public class LinkV1
{
    [DataMember(Name="href")]
    public string Url { get; set; }

    [DataMember(Name="rel")]
    public string Relationship { get; set; }
}

结果如下:

<ArrayOflink xmlns:i="...." xmlns="...">
  <link>
    <href>/users</href>
    <rel>users</rel>
  </link>
  <link>
    <href>/features</href>
    <rel>features</rel>
  </link>
</ArrayOflink>

------------ 第二个版本

好吧,不是我想要的安静,所以我尝试了经典的 XmlSerializer,但是......哦不,如果根元素,你不能指定根元素和集合元素的名称是一个集合...

代码如下:

[XmlRoot("link")]
public class LinkV2
{
    [XmlAttribute("href")]
    public string Url { get; set; }

    [XmlAttribute("rel")]
    public string Relationship { get; set; }
}

结果如下:

<ArrayOfLinkV2>
  <LinkV2 href="/users" rel="users" />
  <LinkV2 href="/features" rel="features" />
  <LinkV2 href="/features/user/{keyUser}" rel="featuresByUser" />
</ArrayOfLinkV2>

------------ 第三个版本

使用 XmlSerializer + 根元素:

[XmlRoot("trick")]
public class TotallyUselessClass
{
    [XmlArray("links"), XmlArrayItem("link")]
    public List<LinkV2> Links { get; set; }
}

及其结果:

 <trick>
  <links>
    <link href="/users" rel="users" />
    <link href="/features" rel="features" />
    <link href="/features/user/{keyUser}" rel="featuresByUser" />
  </links>
</trick>

很好,但我不想要那个根节点!! 我希望我的集合成为根节点。

这里是限制条件:

  • 序列化代码是通用的,它适用于任何可序列化的东西
  • 逆向操作(反序列化)也必须有效
  • 我不想对结果进行正则表达式(我直接在输出流中序列化)

我现在的解决方案是什么:

  1. 编写我自己的 XmlSerializer
  2. 在 XmlSerializer 处理集合时使用技巧(我试过,让它找到一个 XmlRootElement 并将其复数化以生成它自己的 XmlRootAttribute,但这在反序列化时会导致问题 + 项目名称仍然保留类名称)

有什么想法吗?

在这个问题上真正困扰我的是,我想要的似乎真的非常非常简单...

最佳答案

好的,这是我的最终解决方案(希望它对某人有所帮助),它可以序列化一个普通数组,List<>、HashSet<>...

要实现这一点,我们需要告诉序列化程序使用哪个根节点,这有点棘手...

1) 在可序列化对象上使用“XmlType”

[XmlType("link")]
public class LinkFinalVersion
{
    [XmlAttribute("href")]
    public string Url { get; set; }

    [XmlAttribute("rel")]
    public string Relationship { get; set; }
}

2) 编写一个“smart-root-detector-for-collection”方法,它将返回一个 XmlRootAttribute

private XmlRootAttribute XmlRootForCollection(Type type)
{
    XmlRootAttribute result = null;

    Type typeInner = null;
    if(type.IsGenericType)
    {
        var typeGeneric = type.GetGenericArguments()[0];
        var typeCollection = typeof (ICollection<>).MakeGenericType(typeGeneric);
        if(typeCollection.IsAssignableFrom(type))
            typeInner = typeGeneric;
    }
    else if(typeof (ICollection).IsAssignableFrom(type)
        && type.HasElementType)
    {
        typeInner = type.GetElementType();
    }

    // yeepeeh ! if we are working with a collection
    if(typeInner != null)
    {
        var attributes = typeInner.GetCustomAttributes(typeof (XmlTypeAttribute), true);
        if((attributes != null)
            && (attributes.Length > 0))
        {
            var typeName = (attributes[0] as XmlTypeAttribute).TypeName + 's';
            result = new XmlRootAttribute(typeName);
        }
    }
    return result;
}

3) 将该 XmlRootAttribute 推送到序列化器中

// hack : get the XmlRootAttribute if the item is a collection
var root = XmlRootForCollection(type);
// create the serializer
var serializer = new XmlSerializer(type, root);

我告诉过你这很棘手 ;)


要改善这一点,您可以:

A) 创建一个 XmlTypeInCollectionAttribute 以指定自定义根名称(如果基本复数形式不符合您的需要)

[XmlType("link")]
[XmlTypeInCollection("links")]
public class LinkFinalVersion
{
}

B) 如果可能,缓存您的 XmlSerializer(例如在静态字典中)。

在我的测试中,实例化一个没有 XmlRootAttributes 的 XmlSerializer 需要 3 毫秒。 如果您指定 XmlRootAttribute,大约需要 80 毫秒(只是为了拥有自定义根节点名称!)

关于C# Xml序列化、集合和根元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11781606/

相关文章:

c# - WCF RIA 服务 - 加载多个实体

c# - 模拟成员变量

c# - 如何在asp.net-core-webapi中创建路由?

c# - 绘图应用程序使用哪种设计模式

java - Spring 4 + Sitemesh 与 Java 配置和没有 xml

javascript - Chrome 表示无法读取未定义的属性 'nodeName',IE6 没问题,使用 Google Map API

xml - 如何将一些 XML 元素包含在边界框中?

c++ - 处理可能的空指针的类的 boost 序列化

java - 当我有一个黑匣子要转换为字节数组或从字节数组转换时,如何在 Java 中进行序列化和反序列化?

java - 是否有一个 Java JSON 库使用与 XMLEncoder 相同的模式