当前位置导航:炫浪网>>网络学院>>网页制作>>ASP.NET教程

通过XML模板替换实现对象的灵活序列化

  前阵子在写LINQ2Douban的时候碰到关于XML序列化的场景。通过Douban api添加和更新数据的时候都需要Post一个xml entry,如:

  添加活动(xml中用%%括起来的部分是需要填写的部分,为了精简删除了xmlns)

  view sourceprint?01 <?xml version="1.0" encoding="UTF-8"?>

  02 <entry>

  03   <title>%title%</title>

  04   <category scheme="http://www.douban.com/2007#kind" term="http://www.douban.com/2007#%Category%"/>

  05   <content>%Content%</content>

  06

  07   <db:attribute name="invite_only">%IsInviteOnly%</db:attribute>

  08   <db:attribute name="can_invite">%CanInvite%</db:attribute>

  09   <gd:when endTime="%Duration.End%" startTime="%Duration.Start%"/>

  10   <gd:where valueString="%Where%"/>

  11 </entry>

  一下子能想到的方法有两个——通过XmlSerializer或在entity class上实现IXmlSerializable接口来实现,但很快发现有几个问题没法解决:

  1、XmlSerializer不支持泛型集合的序列化,而我在定义entity class时用了不少IList和IDictionary,如db:attribute我就定义成IDictionary

  2、XmlSerializer只能生成完整的element和attribute,像上面那段xml里<category>节点term属性里变化的只有后面%Category%部分,这就没法生成了

  3、存在添加和更新的post内容不一样的情况,这就意味着同一个entity class,存在多种序列化方案

  4、douban的xml entry格式可能会更改,而我不希望因此而更改代码

  想来想去,最好的方法是通过XML模板+反射(简称XMl模板替换)来生成了,就像上面的xml etnry里面%%括起来的部分,替换掉就可以了,这样可以解决上述的四个问题。除了提供和XMLSerializer功能相同的序列化之外,XML模板替换还要满足下面这些要求:

  1、可以序列化实现IEnumerable的集合,这是最常用的集合,当然大多数的泛型集合也是应用了IEnumerable的

  2、提供更灵活的替换。XmlSerializer实现的序列化顺序是”A(B(c)B)A”,对于子对象的序列化只能是嵌套的模式,而XML模板替换可以实现任何层次的替换。

  3、为每种类型的对象提供通用的序列化方式,不需要任何Attribute定义,不需要修改对象的定义。对于给定的object和XML模板,通过发射获取属性值进行XML替换后生成XML内容;对于相同的object,提供不同的XML模板就能生成不同的XML。

  4、通过修改XML模板即可修改序列化结果

  下面给出一个修改过的RSS的XML模板,这次Code4Fun的目的是在最后实现这个模板的替换,并且完成一个能够实现上述功能的Helper class。

  特别的地方:

  1、<category>节点:通过”.”可访问子对象的属性,如果你希望获取Domain的长度可以写成”%Category.Domain.Length%”

  2、<noReplacement>节点:该节点不包含任何替换信息,当进行替换处理时应当忽略

  3、<skipHours>节点:SkipHours是一个List<int>集合,我们希望能够根据SkipHours的值,展开多个<hour>节点

  4、<as:scope>节点:<scope>是模板定义,声明<scope>节点内包含的子节点在Channel.Items对象的作用域中,所有%%(不包括%./Category.Name%)的属性都是对Items对象的属性访问。由于此处Items对象是List<RssItem>集合,所以将循环生成多个<item>。Scope的含义类似于程序域,支持多个scope的嵌套,Scope定义不会出现在最后生成的xml中。

  5、<channelCategory>节点:<channelCategory>节点在Items的作用域中,但我们可以通过”./”访问外部scope的属性,类似dos文件路径,如果要访问上上级scope,则是”././”。%./Category.Name%表示访问Channel对象的Category属性的Name属性。

相关内容
赞助商链接