【情景介绍】
高校平台中有很多子系统,而子系统之间或多或少的会进行一些数据的交互,我们采用的是分布式部署,那么如何让子系统进行通信呢?我们选择的是webservice。在这里我们要求每个客户端都自定义了一个名为mgr-beans的xml文件,方便去调用外部接口。
但是现在问题来了,如果我拿到的接口name和url是正确的,但是xml节点写错了,那就调不到这个接口了。比如把form写成了from,还真不容易发现。别以为这是小问题,bug没有什么大小可言,只要是出错了,就是大问题呀。
如何避免这个问题呢?看到struts和spring的配置文件了么?在写这些文件的时候总会有智能提示,而且在你写错的时候,还会显示红色波浪线,够人性化吧。而完成这些验证工作的默默工作者就是——dtd和xsd。只要你为xml提供了这两个其中一个,Ecplise就会自动根据dtd或者xsd去检测xml的规范。
【实例演示】
先晒一下我们的xml:
<?xml version="1.0" encoding="UTF-8"?> <beans> <ejb-beans> <ejb-bean id="user-userbean"> <property name="name" value="UserBeanImpl/remote" /> <property name="url" value="localhost" /> </ejb-bean> </ejb-beans> <webservice-beans> <webservice-bean id="user-userservice"> <property name="name" value="mgr.jc.webservice.fortest.IUserBean" /> <property name="url" value="http://jialin:8080/gxpt_mgr_jc_service_fortest_impl-0.0.1-SNAPSHOT/UserBeanImpl" /> </webservice-bean> </webservice-beans> </beans>
特别简单的xml,很清晰,但是如果写错了,还真一时半会看不出来。所以又改动了一下,修改了根节点:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://mfxuan.free.800m.net/webservice-v1.0.xsd"> <!--省略其他代码-->
<?xml version="1.0" encoding="UTF-8"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="beans" > <xsd:complexType> <xsd:all> <xsd:element name="ejb-beans" maxOccurs="1" minOccurs="1"> <xsd:complexType> <xsd:sequence> <xsd:element name="ejb-bean" type="properties" maxOccurs="unbounded" minOccurs="1"/> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="webservice-beans" maxOccurs="1" minOccurs="1"> <xsd:complexType> <xsd:sequence> <xsd:element name="webservice-bean" type="properties" maxOccurs="unbounded" minOccurs="1"/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:all> </xsd:complexType> </xsd:element> <xsd:complexType name="properties"> <xsd:sequence> <xsd:element name="property" maxOccurs="2" minOccurs="2"> <xsd:complexType> <xsd:attribute name="name" use="required"> <xsd:annotation>用法如下</xsd:annotation> <xsd:simpleType> <xsd:restriction base="xsd:string"> <xsd:enumeration value="name"/> <xsd:enumeration value="url"/> </xsd:restriction> </xsd:simpleType> </xsd:attribute> <xsd:attribute name="value" type="xsd:string" use="required"/> </xsd:complexType> </xsd:element> </xsd:sequence> <xsd:attribute name="id" type="xsd:string" use="required"/> </xsd:complexType> </xsd:schema>
Eclipse也不用做任何操作就可以直接用xsd来验证+智能提示+自动补全。如图所示:
【知识讲解】
首先介绍一下xsd:xsd是 XML Schema Definition的简写。是用来描述 xml 文档结构的。其实描述 xml 文档结构的还是一种语法,叫做dtd (Document Type Definition)。dtd虽然可以完成大部分的功能,但它却不是规范的 xml 格式,而且支持的数据类型也少。xsd则是基于xml格式的dtd的替代者。如果你足够细心,你会发现struts配置文件用的是dtd的,而spring用的是xsd。
其实说白了,xsd只包含2类内容——xsd元素 + xsd验证器。而xsd元素既包含element和attribute这些基本的单一元素,也包含如complexType,simpleType等复合元素。xsd验证器则包含类型、长度、出现次数等。具体内容详见:XML Schema 参考手册。
现在我解释一下上面的xsd中的一些元素结构。
这个schema文档是以xsd:schema作为根节点的。xmlns是xml namespace的意思。xmlns:xsd="...",是为命名空间指定一个别名xsd。我们通过别名就可以使用它定义的元素了,比如xsd:element。而这个网址,也就是这个xml的namespace。它对应的则是一个dtd规范,它里面定义了在所有的xml schema中的元素和验证器的名称和使用规范。有兴趣的可以点这里进行查看。
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
第3行则是定义了一个元素,以别名xsd:element开头。name值就是节点的名称。
<xsd:element name="beans" >第4行则说明beans是一个复合元素,它包含有属性元素或者其他element元素等。
<xsd:complexType>第5行,则是一种xsd的复合类型指示器。复合类型指示器:all表示子元素无顺序,指示器
有七种指示器:Order 指示器:(All,Choice,Sequence)、Occurrence 指示器:(maxOccurs,minOccurs)、Group 指示器:(Group name,attributeGroup name)。具体说明请参考:XSD 复合类型指示器。
<xsd:all>第9行中的maxOccurs和minOccurs则是说这个element出现的最大和最少次数。可以用unbounded表示任意次数。而type则表示它的类型被定义成了properties。这主要是为了多种元素的类型一样时,可以直接引用这种类型,不再重复定义。
<xsd:element name="ejb-bean" type="properties" maxOccurs="unbounded" minOccurs="1"/>
第30行中的use="required" 表示element必须包含名为name的属性。
<xsd:attribute name="name" use="required">
第32-37行则是一个属性值的限定,只能选择name或者url。
<xsd:simpleType> <xsd:restriction base="xsd:string"> <xsd:enumeration value="name"/> <xsd:enumeration value="url"/> </xsd:restriction> </xsd:simpleType>
这是我第一次写xsd,在写之前还是有点小忧虑的,怕写不出来,又是查w3school,又对照着spring的xsd去比较。还好最终的效果还是出来了,虽然没有对属性值进行过多的约束,不过节点已经都规定好了,在一定的程度上可以将认为错误减少很多了。