深入学习XML和XSD、定制XML数据交互规范


最近制定了报表引擎数据交互的XML规范,

没时间写总结,先列出下面的参考资料:

http://www.w3school.com.cn/schema/schema_example.asp

http://www.w3.org/TR/xmlschema-0/

http://maven.apache.org/xsd/(很好的规范参考)

http://www.opentravel.org/Specifications/OnlineXmlSchema.aspx(很好的规范参考)


http://blog.csdn.net/zhengyeqing520/article/details/6091656


报表引擎XML规范“TRE标准”的制定和实施

 

一、“TRE标准”的来源和背景

我们可以看到,很多项目的XML结构采用了“OTA标准”,报表引擎在这一方面借鉴了“OTA标准”,制定了自己的XML标准,我们称之为“TRE标准”。

 

1、为什么要制定这样一个标准?它有什么作用?

因为报表引擎的一些参数传递采用了XML的结构,XML是一种较好的组装数据的方式,内容丰富,易于扩展,也得到了广泛的认可。

报表引擎支持多个不同的项目,报表引擎是提供服务的一方,应用端需要通过一套规范的流程来调用报表引擎的服务,无论是应用端提交的指令还是数据,都需要遵循一定的格式。我们通过XML来定义这种格式,一是可以验证,二是方便解析。(最原始的方式是自己组装字符串,用%&等字符来分割,用正则表达式去验证,用split等方法去解析……这种方式很麻烦,不太适合复杂类型的数据)。

标准化的东西,一个是容易使用(比如封装、解析),二是容易判定(是否符合标准),三是便于版本控制,四是体系容易扩展。

 

2、“TRE标准”是基于什么规范?参考了哪些标准?

1)“TRE标准”是基于W3CXML规范制定的,除了W3CXML规范外,业界还有比如微软的OOXML规范、ISORELAX NG规范等。

2)“TRE标准”主要参考了“OTA标准”、SpringXML配置文件标准、MavenXML配置文件标准以及Apache的一些知名项目的XML配置文件标准,包括它们的数据格式、类型、验证方式、版本定义、命名方式等。下面列举一部分示例:

 

1.1  Maven标准XSD的头部信息

1.2  OTA标准的XSD头部信息

 

二、制定“TRE标准”的过程

1、选择定义方式

规范XML格式的方法最常见的有两种:一是通过DTD去定义和验证,二是通过XML Schema去定义和验证。DTD的方式较古老,现在用的不是很多Unfortunately the DTD Syntax was not that powerful. Written in SGML, DTDs are also not as easy to handle as XML.),而Schema要更灵活,功能更强大,使用更广泛。鉴于报表引擎XML数据结构还是比较复杂,需要较好的扩展性,且考虑到Schema使用的广泛性,我们选择了XML Schema这种方式去定义

2、选择XML规范(和编程工具)

首先我们想到的就是基于W3C的规范。它是最老的,也是用得最多的规范,基于这个规范,可以很好的定义和验证XML文档。

不过,我们也没有用到十分特殊的语法,所以,对于其他规范,比如RELAX NG,应该也是兼容的。

XML相关的编程工具,有Apaches XercesDOM4JJDOMMSVMulti Schema ValidatorMSV),JARVJava API for RELAX Verifiers)等。经过很多的比较和测试,我们选择了DOM4J作为解析XML的工具,而XML的验证,是基于Java自带的API——JaXP 1.1 TraXjavax.xml.*),相比之下,其效率是最好的

 

3、定义便于扩展的XML数据结构

直接编写XML,考虑到各种情况,如果不好统一,也可以弄出几个版本。

 

4、定义描述和验证XMLSchema文档

XML的需求上,定义它的Schema文档,主要考虑到格式的验证数据结构的合理性。


5、编写验证XML的程序 

使用定义好的xsd文件去验证xml文档。这里写了很多个程序去验证xml,包括dom4jJARVMSV等等选择效果最好的那个

 

6、定义XML的体系和版本

类似于Maven等定义的版本方式,但是没有采用“OTA”那种复杂的版本定义方式,主要是我认为“OTA”的版本控制过于复杂和冗余。

目前我只制定了ReportAddRQ.xml, Version 1.0.0。我认为报表引擎的XML版本更新不会太频繁,因为每一个版本都对应于不同的解析和验证程序,所以为了简便起见,类似于Version 1.0.0(完整的定义为aa.bb.cc,可以从0.0.099.99.99)这种版本号,aa表示XML的体系,例如1就代表ReportAddRQ这个体系(即新增报表请求的xml);中间那位数字bb代表大版本号,用于区分一些不同的应用版本(包括一些个性化的要求);后面的那位数字cc代表小的版本号,即,在原来版本的基础上进行的一些里程碑式的升级更新。

程序在验证和解析XML的时候,只需要判断这个Version便可以立即从API方法里面寻找到合适的解析、验证方法。

 

7、编写整体XML的传递、验证、解析、封装流程

如题。需要提到的一点是,XML的传送最好采用加密传输的方式,关于加密解密算法,不再本文讨论的访问内。

另外,传递的时候,版本号要单独传递(独立于XML文档之外),以便接收方拿到版本号之后,对xml文档进行验证和解析。


三、“TRE标准”解密


1、头部定义


我们定义了默认的名称命名空间(name space),并在名称命名空间中融入了版本号。

xmlns="http://report.zollty.com/TRE/1.0.0"

第二,我们定义了schema文件的网络Location,以便可以直接通过网络下载此xsd文件,对xml进行验证。

xsi:schemaLocation="http://report.zollty.com/TRE/1.0.0 http://report.zollty.com/schema/ReportAddRQ-1.0.0.xsd"

第三,看看它的命名规范,root元素名叫“RepoortAddRQ”,ReportAdd是功能性描述,RQRequest,代表这是一个“请求”,同理,如果是RS(Response),则代表“响应、返回”。其他元素、属性都是以大写开头,“驼峰式”命名法。

第四,xml内容的开始部分,定义了xml的属性(XmlAttr),包含了VersionTokenTimeStamp等基本信息。这一部分的内容针对不同的XML Version,是可以任意改变的。

 

2元素Type的定义

我采用了元素和元素的Type分开定义的方式。以XmlAttr为例,如下图:

3.3  XmlAttr元素的定义

 

 

3.4  XmlAttr元素Type的定义(片段)

这种定义方式的好处在于:使元素的定义更加清晰,而且使得某些类型可以重用。

 

3XML组装、验证和传递

1)组装入口,示例如下:

if(VERSION_1_0_0.equals(version)){

xmlStr = createXmlVer1_0_0(xmlParams,version);

}

就是根据不同的版本,调用不同的方法去组装XML

2)传递方式,示例如下:

xmlStr = EncryptTools.getEncryptedStr(attrsXml);

originalStr.append("&").append(version);

originalStr.append("&").append(xmlStr);

其中xmlStr加密过,类似于d94b3c5a7f646d8e....这种形式,同时注意到传递了版本号version参数。

3XML的验证,入口示例如下:

// xml格式校验

InputStream xsdIn = RequestTools.class

.getResourceAsStream("ReportAddRQ-"+version+".xsd");

StreamSource xsdSource = new StreamSource(xsdIn);

XmlSaxErrorHandler errorHandler = XMLUtils.xmlValidator(xmlStr, xsdSource);

if(!errorHandler.isSuccess()){

throw new RuntimeException(errorHandler.getErrorMsg());

}

根据不同的版本号,调用不同的验证规则xsd文件去验证它。

关于这个XMLUtils里面的验证方法,我写了一整套,下面仅列举其中的核心方法:

 

 

 

 

4XML的解析和封装

XML解析出来,封装成JavaBean,我用的是dom4j,仅举一例来说明吧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/**
  * 解析任务请求的特定格式的XML
  * @param xml 待解析的XML字符串,其格式应严格为:
  * @return 封装好的参数Bean
  * @author zollty <br>2012-12-17
  */
public  static  ParamsXMLBean xmlParser(String xml){
     
     try {
     
         StringReader sr =  new  StringReader(xml);
         
         SAXReader reader =  new  SAXReader();
         reader.setEncoding( "UTF-8" );
         Document document = reader.read(sr);
         
         Element root = document.getRootElement();
         
         List<Element> formAttrsElement = root.element( "FormAttrs" ).elements();
         Map<String,FormVO> formAttrs =  new  LinkedHashMap<String, FormVO>();
         
         FormVO fvo =  null ;
         String name =  null ;
         for  (Element element : formAttrsElement) {
             name = element.element( "Name" ).getText().trim();
             fvo =  new  FormVO();
             fvo.setName(name);
             fvo.setValue(element.element( "Value" ).getText().trim());
             if null !=element.element( "Title" ) ){
                 fvo.setTitle(element.element( "Title" ).getText().trim());
             } else {
                 fvo.setTitle( "" );
             }
             if null !=element.element( "DisName" ) ){
                 fvo.setDisName(element.element( "DisName" ).getText().trim());
             } else {
                 fvo.setDisName( "" );
             }
             formAttrs.put(name, fvo);
         }
         
         List<Element> otherAttrsElement = root.element( "OtherAttrs" ).elements();
         Map<String,OthersVO> otherAttrs =  new  LinkedHashMap<String, OthersVO>();
         OthersVO ovo =  null ;
         for  (Element element : otherAttrsElement) {
             name = element.element( "Name" ).getText().trim();
             ovo =  new  OthersVO();
             ovo.setName(name);
             ovo.setValue(element.element( "Value" ).getText().trim());
             if null !=element.element( "Extra" ) ){
                 ovo.setValue(element.element( "Extra" ).getText().trim());
             }
             otherAttrs.put(name,ovo);
         }
         
         ParamsXMLBean paramsXMLBean =  new  ParamsXMLBean();
         paramsXMLBean.setFormAttrs(formAttrs);
         paramsXMLBean.setOtherAttrs(otherAttrs);
         
         return  paramsXMLBean;
     
     } catch  (Exception e) {
         return  null ;
     }
}



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值