以下是我需要的样本:
<links> <link href="/users" rel="users" /> <link href="/features" rel="features" /> </links>
在这种情况下,对象是’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>
尼斯,但我不想要那个根节点!
我希望我的收藏是根节点.
以下是约束:
>序列化代码是通用的,它可以与任何可序列化的方式一起使用
>反操作(反序列化)也必须工作
>我不想正则表达式(我在输出流中直接序列化)
我现在的解决方案是什么
编码我自己的XmlSerializer
> Trick XmlSerializer当它与一个集合工作(我试过,找到一个XmlRootElement和plurialize它来生成自己的XmlRootAttribute,但是当反序列化项目名称仍然保持类名时会导致问题)
任何想法 ?
在这个问题上真正困扰我的是,我想要的似乎真的很简单
解决方法
要实现这一点,我们需要告诉serializer什么根节点使用,这是一个棘手的…
1)在可序列化的对象上使用’XmlType’
[XmlType("link")] public class LinkFinalVersion { [XmlAttribute("href")] public string Url { get; set; } [XmlAttribute("rel")] public string Relationship { get; set; } }
2)编写一个“智能根检测器收集”方法,这将返回一个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需要3ms.如果指定一个XmlRootAttribute,它大约需要80ms(只需要一个自定义的根节点名称!)