`
pangwu86
  • 浏览: 117514 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

XBlink中关于XML/JSON格式中引用对象的路径的实现思路

阅读更多

在将一个对象序列化过程中,引用对象的处理是一个常见问题。


随着新版本XBlink的即将推出,这个老大难问题就需要慎重解决。


在0.7.0版中,引用虽然已经能够正确处理,但是实现方式是采用了对象出现先后顺序为标记,采用数字的方式来实现引用。


例如 A包含B,B包含C,C包含A,C也包含B。生成的XML如下:



<A>
  <B>
    <C>
      <A ref="1"/><!-- A是第一个序列化的对象,ID设置为1 -->
      <B ref="2"/><!-- B是第二个序列化的对象,ID设置为2 -->
    </C>
  </B>
</A>

 

这个摸样虽然没错,但是在难以阅读。(毕竟序列化为XML的优点之一就是其可读性好,如果不好,那还不如用其他格式)


新版本的开发决定彻底解决这个问题,让引用路径可以清楚表示出其对象位置。


思考后,解决方式就是生成常见的两种路径:相对路径 绝对路径


在这个实现过程中,看了下Fastjson与XStream的实现方式,发现以下几点问题:


首先说说温少的Fastjson的实现方式


这里有温少的一个思路最终实现


这里的路径感觉有稍许混乱,有的是相对路径,例如使用..来引用上级对象,但也有几个特殊符号,使得有的路径又变成了绝对路径,例如使用对于根节点使用$来表示,自身使用@来表示。


个人认为这样会产生一个问题,例如上面那个ABC的例子,可以有两种表现形式


<A>
  <B>
    <C>
      <A ref="$"/>
      <B ref="../.."/>
    </C>
  </B>
</A>
<!-- 下面这种也是正确的 -->
<A>
  <B>
    <C>
      <A ref="../../.."/>
      <B ref="$.B"/>
    </C>
  </B>
</A>

 

像例子中关于B节点就有两种不同的表示方式,一个文件中会混杂这两种格式,这就是个人觉得有稍许混乱的原因。


代码的话查看com.alibaba.fastjson.serializer.SerialContext

还有com.alibaba.fastjson.serializer.JSONSerializer的writeReference方法


里面实现是优先判断是否属于那几个特殊符号使用范围,不行再计算路径。


路径是通过一个链表形式存放的,不断查找父节点,拼装路径,具体的还是看源码吧。


再谈谈XStream的实现方式


XStream采用了常见的相对路径来表示位置关系(个人比较喜欢这个)。


代码看com.thoughtworks.xstream.io.path包。


简单分析下几个类的作用:


Path 就是封装路径用的对象,里面有着计算相对路径的方法。


PathTracker 名字都告诉你了,Tracker!里面有一个栈,进去一个节点,把节点名称压入栈中,退出这个节点,弾栈,也就是说记录当前路径信息,通过它可以获得你当前所在节点的绝对路径。


PathTrackingWriter 一个包装类,里面实际工作的是HierarchicalStreamWriter也就是用来写XML文件的,在写节点开始标签时,调用PathTracker记录那个节点名称,写节点结束标签时,再调用PathTracker 删掉那个节点名称。


PathTrackingReader 与PathTrackingWriter 功能类似,反序列时用的。


最后说下XBlink的实现思路,其实跟XStream差不多,基本就是参考它的,做了一些简化与改进。


详情见org.xblink.core.path包(里面几个类也是借鉴了XStream,哈哈,谁叫XStream是XBlink的老师来)



讲下思路,首先在开始写XML时,生成一个PathTracker实例。

实现一个引用缓存,例如一个key是对象,value是绝对路径的Map,用来记录对象与其绝对路径的关系。

首先一个对象序列化,先去这个缓存查看一下,是否已经存在了,如果没有,那就开始写一个节点,记录下这个节点名称,放入PathTracker中。当你发现有个节点是可以被引用的(可能被引用,后面是不是真的被引用还不知道),就通过PathTracker生成当前这个节点的绝对路径,将这个类与路径记录引用缓存中,然后序列化下一个对象。

当发现要某个对象是要在缓存中存在的了,那就生成当前路径(也是一个绝对路径),通过一个算法,将此路径与缓存中那个对象的绝对路径进行比较,生成相对路径


在代码上如果变通一下的话,你可以设置一个开关,关于引用是采用相对路径还是绝对路径(这两者你都可以拿到)

这样不但你让用户多了一个选择(更人性化),如果使用绝对路径,还能减少一次计算路径的开销,提高了效率。


以上就是一些个人想法,欢迎大家提出意见探讨。

 

2
8
分享到:
评论
2 楼 han0917 2013-12-09  
我想问下我使用XBlink序列化对象为xml的时候,对某字段A设置了“”,空串。序列化后xml格式为<A/> ,有没有办法变成<A></A>这样呢?
1 楼 rodoke 2013-06-06  
最近使用XBlink生成xml 出现了个问题,因为有多层嵌套,不同的集合中有相同的对象,就出现了很多ref的引用,反序列化的时候就直接失败,经过测试 如果没有这么复杂的嵌套,类似这种:
  <?xml version="1.0" encoding="UTF-8" ?>
- <testUser>
- <userList>
- <user>
  <userName>kkk</userName>
  <userSex>sss</userSex>
  </user>
  <user ref="../user" />
  </userList>
  </testUser>
这样的反序列化是没问题的,请问这样的问题要怎么解决

相关推荐

Global site tag (gtag.js) - Google Analytics