C#XML序列化收集和根元素 [英] C# Xml serialization, collection and root element

查看:192
本文介绍了C#XML序列化收集和根元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用程序中的数据流序列化对象。
这里是什么,我需要一个示例:

My app serializes objects in streams. Here is a sample of what I need :

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

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

In this case, the object is a collection of 'links' object.

-----------第一版

-----------First version

起初我使用了的DataContractSerializer 但是你不能序列成员属性(的来源

At first I used the DataContractSerializer, however you cannot serialize members as attributes (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>



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

----------- Second version

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

Ok, not quiet what I want, so I tried the classic XmlSerializer, but... oh nooo, you cannot specify the name of the root element & of the collection's elements if the root element is a collection...

下面是代码:

[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>



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

----------- Third version

使用的的XmlSerializer +一个根元素:

using XmlSerializer + a root element :

[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>



不错,但我不希望这样的根节点!
我希望我的收藏是根节点

Nice, but I don't want that root node !! I want my collection to be the root node.

下面是约束上:


  • 序列化代码是通用的,它与任何可序列化

  • 逆运算(反序列化)的作品有工作太

  • 我不想正则表达式的结果(我直接在输出流序列化)

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

What are my solutions now :


  1. 编码我自己的XmlSerializer

  2. 招数XmlSerializer的,当它与集合作品(我试过了,有它找到一个XmlRootElement将并plurialize它自己产生XmlRootAttribute,但引起的问题反序列化+项目名称时,仍保持为类名)

任何想法?

真正困扰我的这个问题,是我想要的似乎是真的真的很简单...

What really bother me in that issue, is that what I want seems to be really really really simple...

推荐答案

好吧,这是我的最终解决方案(希望它可以帮助别人),可序列化一个普通数组,列表<>,HashSet的<> ...

Ok, here is my final solution (hope it helps someone), that can serialize a plain array, List<>, HashSet<>, ...

要实现这一目标,我们需要通知该序列化使用的根节点,它是一种棘手的...

To achieve this, we'll need to tell the serializer what root node to use, and it's kind of tricky...

1)使用序列化的对象上XmlType将

1) Use 'XmlType' on the serializable object

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

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



2)的代码智能根探测器换集方法,这将返回XmlRootAttribute

2) Code a 'smart-root-detector-for-collection' method, that will return a 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到串行

3) Push that XmlRootAttribute into the serializer

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



我告诉你这是棘手的,)

I told you it was tricky ;)

要改善这一点,您可以:

To improve this, you can :

A)创建XmlTypeInCollectionAttribute指定自定义根名称(如果基本多元化不适合您的需要)

A) Create a XmlTypeInCollectionAttribute to specify a custom root name (If the basic pluralization does not fit your need)

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

b)如果可能的话,你的缓存XmlSerializer的(在例如静态词典)。

B) If possible, cache your XmlSerializer (in a static Dictionary for example).

在我的测试中,instanciating一个XmlSerializer的不XmlRootAttributes需要3毫秒。
如果指定XmlRootAttribute,大约需要80毫秒(正好有一个自定义的根节点的名字!)

In my testing, instanciating a XmlSerializer without the XmlRootAttributes takes 3ms. If you specify an XmlRootAttribute, it takes around 80ms (Just to have a custom root node name !)

这篇关于C#XML序列化收集和根元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆