C#XML序列化收集和根元素 [英] C# Xml serialization, collection and root element
问题描述
我的应用程序中的数据流序列化对象。
这里是什么,我需要一个示例:
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 :
- 编码我自己的XmlSerializer
- 招数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屋!