Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2342267
  • 博文数量: 321
  • 博客积分: 3440
  • 博客等级: 中校
  • 技术积分: 2992
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-24 09:08
个人简介

我就在这里

文章分类

全部博文(321)

文章存档

2015年(9)

2014年(84)

2013年(101)

2012年(25)

2011年(29)

2010年(21)

2009年(6)

2008年(23)

2007年(23)

分类: Java

2011-11-04 10:23:55

摘自:http://blog.sina.com.cn/s/blog_539f8fd6010005kf.html
作者两天忙的七荤八素的,为了HLC和 YG老兄的东东

 正好在改写HLC的程序,涉及到EDI解析的一块,把些经验写下来。HLC的项目用到的是INVOIC,舱单用的是IFCSUM,都是EDIFACT规范。
 首先,EDI是报文文件格式,文件有许多个 Segments 构成,Seg的结构就像“RFF+BM:HLCUSHA040203964”,Seg之间用单引号分隔。每个Seg又由Seg名和多个Composites 组成。Seg名由3个大写字母组成,像上面的例子,RFF就是Seg名。Seg名和Composites 间以及Composites 之间由加号分隔,上面的例子里BM:HLCUSHA040203964就是一个Composite。Composite由一个或多个Data elements 组成,用冒号隔开。如果数据项里有分隔符存在,则用问号做表识。比如一个公司名称里带有单引号,那么这个单引号就要用?'来代替。+号和:号的情况也是一样的。
关于EDI的解析2
上一篇说的Segment及比其更小的结构,再说说Segment以上的结构。

 EDIFACT里有多种报文规范,一般称为Message,每种报文规范对应于一种EDI应用,比如付款凭证是INVOIC,而舱单就是IFCSUM,VESDEP则是发船报文。Message——报文规范规定了一个报文文件的组成形式。整个的报文文件以UNB Segment开头,由UNZ Segment结尾,中间则包含了1..n个Message。
 每个Message都是以UNH Segment(Message header)开头的,后面会紧跟着一个BGM Segment(Beginning of Message),UNH说明报文规范版本,还会包含一个校验码,而BGM则主要用来说明Message Type——报文规范的名称。比如如果是发票报文(INVOIC)则是BGM+380:::COMMERCIAL INVOICE+30800295+9。这里的编号380和"COMMERCIAL INVOICE"都说明了这是一个发票报文。30800295即1004 Composite则说明了发票的编号,最后9即1225 Composite说明了这是一个原始记录(还可以是更改记录、删除记录等等)。每个Message都以UNT Segment结束,UNT Segment会包含开头的UNH Segment里的校验码,还会有整个Message里的Segment条数。
 BGM 和UNT之间所有的Segment用来说明报文内容。这些Segment可以是独立的,也可以多个Segment组成一个Segment Group,用来表明某种比较复杂、无法由一个Segment说明的信息。
 比如在IFCSUM报文规范里,在报文开头的部分,可以加入1..n个CNT Segment来说明整个舱单中货物的总箱量、总毛重等等。然后是
 0070   Segment group 1: RFF-DTM
 这表明,在CNT Segment后可以在报文里加上0..n个0070,这是个由一个RFF Seg(必要)和一个DTM Seg(不必要)组成的group。RFF用来说明提单信息,而DTM则是说明与提单有关的日期信息。
关于EDI的解析3
然后说说EDI实际应用和解析报文的情况

 EDIFACT中的规范是很全的,由专门的委员会编撰,每半年出一次更改后的规范。但在实际应用中,一般都不需要那么全的规范,所以具体的使 用者(某个政府机构或者航运公司等等)会根据自己的需要出一个自己的规范,这个规范必然是EDIFACT的一个子集。这样做一般都是出于解析效率的考虑。
 解析报文的方法——我没见过EDI解析的代码,只能说说自己做EDI解析的经验了。一般来说,一个Message解析完成后,其解析结果在数据库中会对应与主表中的一条记录,以及多个副表中的多条记录。主表——副表之间一般是由主表主键担任外键的形式相关联。
 解析过程中还有个比较重要的问题是,解析过程中的异常处理。如果某个Message有错误,怎样定位错误,怎样处理这个Message或者是处理整个的报文文件。这些问题在一开始设计时都必须考虑完备。
EDI解析
我第一次做EDI解析时,完全是面向流程的,虽然这个Message很简单,但程序最后还是很难看。一堆的porcedure和function,隔了半年自己都看不懂了

 然后做舱单的时候,由于是从delphi改到了java,而且自己对于EDI解析和OO的认识有了一点点的改观,于是又设计了一堆的类,虽然类的层次还是比较清楚,而且框架结构也比较清楚,对于扩展和修改都比较方便,但是总觉得有点不太对劲
 我的设计是:有一系列有相同接口的Segment parser类,负责Segment的解析;有几个结构处理类,处理Message和Segment group以及相互之间关系;有几个builder类,根据Message和Segment group创建对象;然后有多个adapter类处理与数据库之间的联系。
 现在仔细的分析下发现的问题是:在各个类、包的责任上还不是划分的很合理。首先,在Segment层次上做基础的信息分析有点太小,Segment parser包很容易大量增加。同时,Message的结构一旦很复杂,Message框架处理类内部结构会更加复杂。而Message框架处理类和builder类在功能上有点重叠。处理数据库的adapter层没有什么问题。
 
改动的预想:按照以责任—接口来进行类的设计的原则,对于某些不是很复杂的segment or segment group到实体对象的映射可以放在一个类中完成,而复杂的group的处理则由多个类合作完成。这样,类的层次就能够更加合理化。
 比如,发票中的金额细目group。INVOIC规范里的1470,即Segment group 38:ALC-ALI-DTM-SG39-SG40-SG41-SG42-SG43,是个两层结构的、由十几种Segment构成的复杂结构。实际情况是,只有ALC和MOA segment一对一构成细目组。
 ALC+C+DEST DELIVERY CHGE
 MOA+282:740:USD
 
 这样,group38的解析包可以直接调用字符串处理函数从报文中取出需要的信息——费目“DEST DELIVERY CHGE”,金额“740”,币种“USD”。这样少了10几个Segment处理类,少了5、6个结构处理类,只用一个builder类就可以完成比较 简单的金额细目处理。由于Segment处理层是在builder层下面,builder层上面的类直接调用buidler类的接口,不必知道底层的实 现。而一旦需求有更改,只要改动buidler类内部的实现方式就可以了。对builder类层上下都无影响。
阅读(1887) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~