使用CAM机制提高XML验证水平

原创
开发
本文详细叙述了CAM即内容装配机制(Content Assembly Mechanism)的基础用法,优势以及一些验证实例。CAM是一个XML结构验证方法,近年来开发非常迅速。它不仅是一门schema语言,其设计目的是更好地满足业务交流和互操作性要求,它提供了强有力的机制来验证XML结构和语义,使其简洁、易于使用和易于维护。

【51CTO独家特稿】CAM即内容装配机制(Content Assembly Mechanism),它是一个XML结构验证方法,由于它是一个新生事物,文档很少,因此本文就当扫盲了。

XML文档的验证需要确认文档是完整的,并且符合在文档类型定义(Document Type Definition 即DTD)中指定的规则,DTD是最早的规范说明方法,它提供了有用但有限的功能来验证XML文档结构,但只有一点语义;接着出现了XML Schema,它提供了更多灵活性和功能,增强了对结构的支持,并且很好地支持了语义,Schematron,RelaxNG已经尝试提升对语义的支持,但都没有取得什么进展;现在一种全新的技术在OASIS的保护下开发出来了,它就是CAM。

CAM不仅是一门schema语言,其设计目的是更好地满足业务交流和互操作性要求,它提供了强有力的机制来验证XML结构和语义,使其简洁、易于使用和易于维护;它提供了一个上下文机制 -- 一种基于XML自身其它部分或外部参数来动态调整那些应被视为有效的XML实例。

CAM是一个令人兴奋的技术,它的未来充满希望,但它是一个新技术,可能有好有坏;CAM的开发非常迅速,因此在本文中,你可能会发现很多‘在写本文的时候’的字眼。开发团队也很勤奋,你反馈的问题可能很快就会得到修复,而且有些问题可能你还没有发现就已经被修复了。

因此,在写本文的时候,CAM文档还很潦草:有一个正式的规范,一份白皮书,一份PowerPoint演示文稿和一些简要介绍了编辑器和API的网页。还没有明确的指导和教程,本文的目标就是:“CAM:缺少的手册”,扩大CAM文档阵营。

你需要

◆基本上熟悉XPath,CAM大量使用了Xpath定义业务规则,请参考w3School的Xpath教程温习一下。

◆基本上熟悉XML Schema,虽然本文表面上看起来是XML Schema的继承,因为它广泛地依赖于与XML Schema的对比,作为最有效的沟通方法,请参考w3School的XML Schema教程温习一下。

规定合法XML

XML文档是元素的多层次组合,它是一个用于存储任何数量文字或数据结构的树状存储结构,XML文档需要很好的格式,这意味着它只有一个根,其元素和属性必须符合简单的XML语法规则,在XML没有映射到特定的问题域(如数学、书籍协作或金融交易)之前,它都没什么用处,这种映射将抽象的XML区域以一种专业XML语言与你的特定问题对应起来,任何专用语义都必须事先定义好,否则就会被认为是无效的,遭到拒绝。

思考一下下面的顾客地址:

﹤address﹥
﹤address_street﹥221B Baker Street﹤/address_street﹥
. . .
﹤/address﹥

为了在XML Schema中验证这个XML片段,你通常会定义一个如下的结构:

﹤xs:element name="address"/﹥
. . .
﹤xs:element name="address_street" type="xs:string"/﹥
. . .
﹤/xs:element﹥

这些限制条件指出﹤address_street﹥元素必须存在,并且必须包含在﹤address﹥元素内,还必须包含一个字符串。对于一个地址而言,一个简单的字符串值可能是适当的,但其它字段你应该使用更具体的东西,要么是一个专门的字符串(一种衍生的,有限制的字符串)、日期、整数或其它定义类型。
XML Schema是一种基于语法的系统,在它里面你需要同时为语义和结构定义语法;另一方面,Schematron是一个基于规则的系统,你可以使用规则同时指定语义和结构,即你不仅使用规则指定address_street是一个字符串,还用规则指定﹤address_street﹥必须显示在﹤address﹥元素内,XML Schema和Schematron从根本上说语义和结构都是纠缠在一起的。在编程方面耦合度很高,这是不可取的。
相比之下,CAM是一个混合系统,它将结构从语义中独立出来(低耦合),使用规则指定语义,例如address示例看起来象:

﹤as:Structure﹥
﹤address﹥
﹤address_street﹥%street number and name%﹤/address_street﹥
. . .
﹤/address﹥
﹤/as:Structure﹥

﹤as:Rules﹥
﹤as:constraint action="datatype(//address_street,string)" /﹥
﹤/as:Rules﹥

CAM模板的﹤as:Structure﹥小节定义了XML文档的层次结构,实际上它是从XML文档示例复制过来的,只不过将真实数据替换成占位符(以百分号标志出来)而已,因此前面的CAM模板表示是一个使用%street number and number%占位符替换真实数据的XML实例。
﹤as:Structure﹥小节补充了部分语义,它定义了一个元素包含了哪些其他元素,以及顺序,和Schematron不一样,你不需要费力地编写规则代码定义结构,CAM以所见即所得的形式指定结构,而Schematron不得不自己动手写代码,就和使用微软Word字处理软件一样方便,所见即所得形式相对使用RTF文本生成Word文档而言,编写RTF实在是太乏味、太困难了,而且容易犯错,如图1所示。

图1
图1

所见即所得示例,微软Word使用更直观的形式编辑文档(左侧),但这两种方式实际上都在完成同一件事情
即使有一些很酷的工具如XmlSpy或Liquid XML Studio可以帮助你实现所见即所得的感觉,XML Schema也不是所见即所得的,思考一下下面的示例代码,它定义了一个cost,范围在1-999,保留2位小数。

﹤xs:element name="cost"﹥
﹤xs:simpleType﹥
﹤xs:restriction base="xs:decimal"﹥
﹤xs:fractionDigits value="2" /﹥
﹤xs:totalDigits value="5" /﹥
﹤xs:minInclusive value="1" /﹥
﹤xs:maxInclusive value="999" /﹥
﹤/xs:restriction﹥
﹤/xs:simpleType﹥
﹤/xs:element﹥

下面显示的两个CAM语法是等同的:

﹤as:constraint action="setNumberMask(//Part/cost,###.##)" /﹥
﹤as:constraint action="setNumberRange(//Part/cost,1-999)" /﹥

CAM模板的﹤as:Rules﹥小节定义了在﹤as:Structure﹥小节中明确嵌入的语义之外的所有语义,包括数据类型、约束、基数、条件等。

CAM的优势

表1总结了相对于XML Schema和DTD,CAM的关键优势,表这每行将会在本文后面介绍,或以后的文章中介绍。

表1

序号 项目 DTD XML Schema CAM 示例/注释
1 隔离结构和业务规则  
2 当前节点固定验证 ﹤quantity﹥将一个整数固定在1到100之间
3 当前节点条件验证 受限的 ﹤zip﹥必须是5位数或10位数
4 跨节点条件验证 受限的 如果﹤state﹥是FL,NV,SD,TX,WA,WY,NH或TN,﹤taxable﹥必须是no,否则就是yes
5 上下文机制 依赖于条件A或B是否符合
6 结构可变性 订购数量超过25kg的顾客必须选择一种物流运送方式
7 参数化引用 从加拿大采购必须符合条件x、y和z,从新西兰订购必须符合条件a、b和c
8 命名空间感知  
9 定义自己的数据类型 不行 可以 可以 ﹤bookNumber﹥必须是8位字符串
10 语法和文档一样 不行 可以 可以  
11 代码重用 受限的 可以 可以 ﹤shipTo﹥和﹤billTo﹥地址包含相同的验证规则
12 工具/编辑器 1  
13 图形化设计器 使用XML Schema设计器时可以设计出复杂的结构
14 所见即所得 使用扩展框架 使用扩展框架 固有的 业务规则语句和它们执行时几乎是一致的,真正做到了按原文所见即所得,
15 采用情况 成熟 成熟 初生婴儿 成熟的稳定性更好,支持也多
16 API Java、Perl、Ruby、.Net Java、Perl、Ruby、.Net Java  
17 开放标准  

表 1 重要的验证特性,DTD,XML Schema和CAM对比表

#p#

CAM编辑器介绍

从http://www.jcam.org.uk/下载最新版本的CAM编辑器,你可以选择下载CAM模板编辑器或Jcam引擎,本文中大部分地方你只需要CAM模板编辑器就够了(Jcam引擎执行CAM验证)。
为了启动CAM编辑器,你可能需要从零开始或从一个现有的XML文件或XSD文件创建一个模板,你会发现实际上创建一个模板还是瞒简单的,我们还是使用W3C的Purchase Order模型开始,将这个文件存储到本地,命名为po.xsd,在编辑器中,选择‘文件’?‘从模型新建模板’,指定你刚刚存储的文件的目录和文件名(如图2所示),在处理这个文件时程序可能会停顿几秒钟,处理完毕后,它会填满根元素comment区域。

图2
图2

从模型新建模板对话框,指定你的XSD文件的路径和文件名,然后从模型中选择根元素,以便CAM编辑器为你创建一个基础的CAM模板

Comment元素是po.xsd文件中所有﹤xsd:element﹥节点的第一个节点(按字母顺序)的名字,这个文件包含两个节点:comment和purchaseOrder。在下面的节选中以粗体显示。你可以在清单1中查看完整的模型。

﹤xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"﹥

﹤xsd:annotation﹥
﹤xsd:documentation xml:lang="en"﹥
Purchase order schema for Example.com.
Copyright 2000 Example.com. All rights reserved.
﹤/xsd:documentation﹥
﹤/xsd:annotation﹥

﹤xsd:element name="purchaseOrder"
type="PurchaseOrderType"/﹥

﹤xsd:element name="comment" type="xsd:string"/﹥

﹤xsd:complexType name="PurchaseOrderType"﹥
﹤xsd:sequence﹥
﹤xsd:element name="shipTo" type="USAddress"/﹥
﹤xsd:element name="billTo" type="USAddress"/﹥
﹤xsd:element ref="comment" minOccurs="0"/﹥
﹤xsd:element name="items" type="Items"/﹥
﹤/xsd:sequence﹥
﹤xsd:attribute name="orderDate" type="xsd:date"/﹥
﹤/xsd:complexType﹥

...

﹤/xsd:schema﹥

清单1 Po.xsd模型

下面是从w3c获得了原始po.xsd模型,本文将使用它构建CAM模板:

﹤xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"﹥

﹤xsd:annotation﹥
﹤xsd:documentation xml:lang="en"﹥
Purchase order schema for Example.com.
Copyright 2000 Example.com. All rights reserved.
﹤/xsd:documentation﹥
﹤/xsd:annotation﹥

﹤xsd:element name="purchaseOrder" type="PurchaseOrderType"/﹥

﹤xsd:element name="comment" type="xsd:string"/﹥

﹤xsd:complexType name="PurchaseOrderType"﹥
﹤xsd:sequence﹥
﹤xsd:element name="shipTo" type="USAddress"/﹥
﹤xsd:element name="billTo" type="USAddress"/﹥
﹤xsd:element ref="comment" minOccurs="0"/﹥
﹤xsd:element name="items" type="Items"/﹥
﹤/xsd:sequence﹥
﹤xsd:attribute name="orderDate" type="xsd:date"/﹥
﹤/xsd:complexType﹥


﹤xsd:complexType name="USAddress"﹥
﹤xsd:sequence﹥
﹤xsd:element name="name" type="xsd:string"/﹥
﹤xsd:element name="street" type="xsd:string"/﹥
﹤xsd:element name="city" type="xsd:string"/﹥
﹤xsd:element name="state" type="xsd:string"/﹥
﹤xsd:element name="zip" type="xsd:decimal"/﹥
﹤/xsd:sequence﹥
﹤xsd:attribute name="country" type="xsd:NMTOKEN"
fixed="US"/﹥
﹤/xsd:complexType﹥

﹤xsd:complexType name="Items"﹥
﹤xsd:sequence﹥
﹤xsd:element name="item" minOccurs="0" maxOccurs="unbounded"﹥
﹤xsd:complexType﹥
﹤xsd:sequence﹥
﹤xsd:element name="productName" type="xsd:string"/﹥
﹤xsd:element name="quantity"﹥
﹤xsd:simpleType﹥
﹤xsd:restriction base="xsd:positiveInteger"﹥
﹤xsd:maxExclusive value="100"/﹥
﹤/xsd:restriction﹥
﹤/xsd:simpleType﹥
﹤/xsd:element﹥
﹤xsd:element name="USPrice" type="xsd:decimal"/﹥
﹤xsd:element ref="comment" minOccurs="0"/﹥
﹤xsd:element name="shipDate" type="xsd:date" minOccurs="0"/﹥
﹤/xsd:sequence﹥
﹤xsd:attribute name="partNum" type="SKU" use="required"/﹥
﹤/xsd:complexType﹥
﹤/xsd:element﹥
﹤/xsd:sequence﹥
﹤/xsd:complexType﹥

﹤!-- Stock Keeping Unit, a code for identifying products --﹥
﹤xsd:simpleType name="SKU"﹥
﹤xsd:restriction base="xsd:string"﹥
﹤xsd:pattern value="\d{3}-[A-Z]{2}"/﹥
﹤/xsd:restriction﹥
﹤/xsd:simpleType﹥

﹤/xsd:schema﹥

你实际上想要purchaseOrder作为根,因此在对话框中将根元素切换成purchaseOrder,然后点击‘确定’生成模板,此时程序会提示你保存模板,保存后模板就在CAM模板编辑器中打开了,如图3所示:

图3
图3

CAM编辑器,从po.xsd模型生成模板后,编辑器同时显示了结构和规则

编辑器中的每个标签容器都涉及到一个视图,结构视图以树形结构显示XML的层次,图3显示定单有一个orderData属性和四个子节点:shipTo,billTo,comment和items。items节点可能包括多个item子节点。CAM编辑器精确地反映了基础XML CAM模板文件(PurchaseOrder/purchaseOrder_from_schema.cam),如下所示,这个文件中的﹤as:AssemblyStructure﹥小节显示的内容实际上与图3中结构视图中的信息是一致的:

﹤as:AssemblyStructure﹥
﹤as:Structure taxonomy="XML" ID="purchaseOrder" reference=""﹥
﹤purchaseOrder orderDate="%YYYY-MM-DDZ%"﹥
﹤shipTo country="US"﹥
﹤name﹥%string%﹤/name﹥
﹤street﹥%string%﹤/street﹥
﹤city﹥%string%﹤/city﹥
﹤state﹥%string%﹤/state﹥
﹤zip﹥%54321.00%﹤/zip﹥
﹤/shipTo﹥
﹤billTo country="US"﹥
﹤name﹥%string%﹤/name﹥
﹤street﹥%string%﹤/street﹥
﹤city﹥%string%﹤/city﹥
﹤state﹥%string%﹤/state﹥
﹤zip﹥%54321.00%﹤/zip﹥
﹤/billTo﹥
﹤comment﹥%string%﹤/comment﹥
﹤items﹥
﹤item partNum="%string%"﹥
﹤productName﹥%string%﹤/productName﹥
﹤quantity﹥%1%﹤/quantity﹥
﹤USPrice﹥%54321.00%﹤/USPrice﹥
﹤comment﹥%string%﹤/comment﹥
﹤shipDate﹥%YYYY-MM-DDZ%﹤/shipDate﹥
﹤/item﹥
﹤/items﹥
﹤/purchaseOrder﹥
﹤/as:Structure﹥
﹤/as:AssemblyStructure﹥

相比之下,XSD文件混合了结构和业务规则,因此维护成本更高,下面是一个完整CAM文件的顶层框架,显示了两个主要的元素:

﹤as:CAM
xmlns:as="http://www.oasis-open.org/committees/cam"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xml="http://www.w3.org/XML/1998/namespace"
xmlns:camed="http://jcam.org.uk/editor"
CAMlevel="1"
version="1.0"﹥
﹤as:Header /﹥
﹤as:AssemblyStructure /﹥
﹤as:BusinessUseContext /﹥
﹤/as:CAM﹥

你可以在清单2中查看完整的CAM模板文件。

清单2 生成的CAM模板

从原始XML模型文件生成的purchaseOrder_from_schema.cam模板:

﹤as:CAM xmlns:as="http://www.oasis-open.org/committees/cam"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xml="http://www.w3.org/XML/1998/namespace"
xmlns:camed="http://jcam.org.uk/editor" CAMlevel="1" version="1.0"﹥
﹤as:Header﹥
﹤as:Description﹥Generated for : purchaseOrder﹤/as:Description﹥
﹤as:Owner﹥To be Completed﹤/as:Owner﹥
﹤as:Version﹥0.1 generator v1.18﹤/as:Version﹥
﹤as:DateTime﹥2008-12-08T12:31:34﹤/as:DateTime﹥
﹤/as:Header﹥
﹤as:AssemblyStructure﹥
﹤as:Structure taxonomy="XML" ID="purchaseOrder" reference=""﹥
﹤purchaseOrder orderDate="%YYYY-MM-DDZ%"﹥
﹤shipTo country="US"﹥
﹤name﹥%string%﹤/name﹥
﹤street﹥%string%﹤/street﹥
﹤city﹥%string%﹤/city﹥
﹤state﹥%string%﹤/state﹥
﹤zip﹥%54321.00%﹤/zip﹥
﹤/shipTo﹥
﹤billTo country="US"﹥
﹤name﹥%string%﹤/name﹥
﹤street﹥%string%﹤/street﹥
﹤city﹥%string%﹤/city﹥
﹤state﹥%string%﹤/state﹥
﹤zip﹥%54321.00%﹤/zip﹥
﹤/billTo﹥
﹤comment﹥%string%﹤/comment﹥
﹤items﹥
﹤item partNum="%string%"﹥
﹤productName﹥%string%﹤/productName﹥
﹤quantity﹥%1%﹤/quantity﹥
﹤USPrice﹥%54321.00%﹤/USPrice﹥
﹤comment﹥%string%﹤/comment﹥
﹤shipDate﹥%YYYY-MM-DDZ%﹤/shipDate﹥
﹤/item﹥
﹤/items﹥
﹤/purchaseOrder﹥
﹤/as:Structure﹥
﹤/as:AssemblyStructure﹥
﹤as:BusinessUseContext﹥
﹤as:Rules﹥
﹤as:default﹥
﹤as:context﹥
﹤as:constraint action="makeOptional(//purchaseOrder/@orderDate)" /﹥
﹤as:constraint condition="string-length(.) ﹤11"
action="setDateMask(//purchaseOrder/@orderDate,YYYY-MM-DD)" /﹥
﹤as:constraint condition="string-length(.) ﹥10"
action="setDateMask(//purchaseOrder/@orderDate,YYYY-MM-DDZ)" /﹥
﹤as:constraint action="makeOptional(//shipTo/@country)" /﹥
﹤as:constraint action="datatype(//shipTo/@country,NMTOKEN)" /﹥
﹤as:constraint action="setNumberMask(//shipTo/zip,######.##)" /﹥
﹤as:constraint action="makeOptional(//billTo/@country)" /﹥
﹤as:constraint action="datatype(//billTo/@country,NMTOKEN)" /﹥
﹤as:constraint action="setNumberMask(//billTo/zip,######.##)" /﹥
﹤as:constraint action="makeOptional(//purchaseOrder/comment)" /﹥
﹤as:constraint action="makeRepeatable(//items/item)" /﹥
﹤as:constraint action="makeOptional(//items/item)" /﹥
﹤as:constraint action="setNumberMask(//item/quantity,######)" /﹥
﹤as:constraint action="setNumberRange(//item/quantity,1-999999)" /﹥
﹤as:constraint action="setNumberMask(//item/USPrice,######.##)" /﹥
﹤as:constraint action="makeOptional(//item/comment)" /﹥
﹤as:constraint action="makeOptional(//item/shipDate)" /﹥
﹤as:constraint condition="string-length(.) ﹤11"
action="setDateMask(//item/shipDate,YYYY-MM-DD)" /﹥
﹤as:constraint condition="string-length(.) ﹥10"
action="setDateMask(//item/shipDate,YYYY-MM-DDZ)" /﹥
﹤/as:context﹥
﹤/as:default﹥
﹤/as:Rules﹥
﹤/as:BusinessUseContext﹥
﹤/as:CAM﹥

规则视图(图3中高亮显示)显示了所有的业务规则,组成了模板的语义,与结构不同,规则存储在文件中时与规则视图不一样,表2将规则视图中的规则集中在一起了,在没有研究这些规则的详细情况时,你可以从它们发现:

◆规则可能是有条件的或绝对的,例如orderDate依赖于它的长度格式要求改变。

◆项目和条件是通过XPath指定的,在CAM中会广泛使用到XPath,它提供了极大的灵活性和清晰度,相比之下,XML Schema 1.0只为高级的xs:unique和xs:key concepts使用XPath。

◆规则可能适用于很广的元素范围,也可能只能适用于很少的元素,XPath支持选择文档的中任何一部分:一个元素、一个属性、所有你给定名称的元素、所有在树中确定位置的元素等。

◆规则是压缩的、简洁的、非常直观的。实际上,正如你将会看到的,编写CAM规则和编写应用程序需求是一样的。

条件 项目 行为
  //purchaseOrder/@orderDate makeOptional()
string-length(.) ﹤ 11 //purchaseOrder/@orderDate setDateMask(YYYY-MM-DD)
string-length(.) ﹥ 10 //purchaseOrder/@orderDate setDateMask(YYYY-MM-DDZ)
  //shipTo/@country makeOptional()
  //shipTo/@country datatype(NMTOKEN)
  //shipTo/zip setNumberMask(######.##)
  //billTo/@country makeOptional()
  //billTo/@country datatype(NMTOKEN)
  //billTo/zip setNumberMask(######.##)
  //purchaseOrder/comment makeOptional()
  //items/item makeRepeatable()
  //items/item makeOptional()
  //item/quantity setNumberMask(######)
  //item/quantity setNumberRange(1-999999)
  //item/USPrice setNumberMask(######.##)
  //item/comment makeOptional()
  //item/shipDate makeOptional()
string-length(.) ﹤ 11 //item/shipDate setDateMask(YYYY-MM-DD)
string-length(.) ﹥ 10 //item/shipDate setDateMask(YYYY-MM-DDZ)

表 2 编辑器中的业务规则:为定单转换XML Schema,让CAM自动生成这些规则。

#p#

CAM验证示例

现在你可以使用手中的模板验证XML文件,W3C网站上除了提供定单模型外,还提供了一个定单实例(PurchaseOrder/po.xml),但下载下来的会有一个印刷错误,图4高亮显示了错误,如果你尝试打开或验证畸形的XML文件,CAM编辑器会显示堆栈转储信息和错误消息(也看图4),并拒绝载入文件。

图4
图4

畸形XML文件:这个图显示了为什么原始的po.xml文件不是合适的,将其载入CAM编辑器时显示出其错误

当你通过将感叹号和左半边尖括号对换位置修复这个错误后(正确的文件是PurchaseOrder/po_corrected.xml),你可以使用CAM编辑器载入这个XML文件,CAM编辑器以XML视图形式显示这个文件,绘制成如结构视图那样的树状结构,如图5所示,目前在模板中相同的元素显示的是真实的值而不是占位符。

图5
图5

XML视图:当你打开一个XML文件时,以XML视图形式显示树形结构,可以折叠和展开

为了验证文档,选择‘运行’?‘运行JCam’,你将会看到如图6所示的Jcam运行对话框,默认情况下,Jcam选择载入的XML文件,应该可以通过它的结构ID如purchaseOrder(这个结构的根)来识别,点击‘完成’关闭这个对话框开始验证,结果显示在主窗口中下方的运行结果视图中,注意验证过程发现了两个错误,尽管在图6中只显示了一个,如果你仔细一看,你会发现有错误的节点上会有一个黄色或红色的图标,在本例中,错误发生在﹤zip﹥元素上,它的父元素﹤shipTo﹥也显示了一个错误图标,甚至根元素﹤purchaseOrder﹥也显示了一个错误图标。同样,你可以推断第二个错误是隐藏在﹤billTo﹥元素中的。

图6
图6

执行验证:验证结果显示在运行结果视图中,每个验证失败的元素或属性都有一个错误标记,它的上级元素就有一个警告标记

这个XML文件在任何XML Schema编辑器中验证都没有错误,为什么在这里验证就失败了呢?运行结果视图中的错误指出zip代码根据CAM模板的定义是无效的,这个模板会检查是否是一个浮点数,因为在美国zip代码要么是5位要么是9位的整数,zip代码的CAM模板规则来自XSD规格说明XSD规格说明简单说明了zip代码是一个十进制数,这一点你可以从清单1中看到:在USAddress复杂类型中查找zip字段,CAM模板生成程序应该避免不用的输入输出。但你可能不同意,我提交的XSD规格说明太宽松了,数据类型应该是一个整数而不是一个十进制数,下面的部分将会介绍如何使用CAM编辑器来纠正这个错误。

当你按照本文的例子进行研究时,你可能会遇到模板没有象预期那样运转,在这种时候要检查两样东西:

◆点击‘工具’→‘验证CAM模板’菜单项查找所有问题。

◆如果你在运行JCam对话框中点击‘完成’按钮,似乎什么事情都不会发生,按‘取消’关闭对话框,然后查看控制台视图中的错误消息,例如,如果你忘记指定要验证的XML文件了,对话框不会禁用完成按钮,控制台视图中报告的错误是‘模板是空的’,这多少会让人有些误解。如果控制台视图什么都没有显示,那就表示一切ok。

#p#

创建业务规则

在结构视图中选择﹤shipTo﹥元素下的﹤zip﹥元素,附加到这个元素的规则显示在项目规则(ItemRules)视图中,在本例中只有一个规则,使用的是setNumberMask谓词。在类别(category)列中的规则上点击右键打开这个规则的上下文菜单,然后选择‘编辑规则’,打开编辑约束规则对话框,如图7所示。

图7
图7

编辑约束规则:为了修复setNumberMask谓词附加到//shipTo/zip元素,选择结构视图中的元素,打开它的上下文菜单,选择编辑规则打开编辑约束规则对话框,点击数字特征码字段明确指定特征码

在数字特征码字段上点击,打开另一个对话框编辑特征码,现在只需要将######.##修改为#####即可,关闭这两个对话框,在主编辑器窗口中,你会看到更新后的规则,重新执行一次验证,//shipTo/zip错误应该不会再出现,只留下//billTo/zip错误,很明显这是一个相同的错误,因此你可以使用相同的手段修复它,但因为//billTo/zip和//shipTo zip的值应该一样,这样就可以使用一个通用的规则而不用每个指定一条规则了,本文的第二部分将会详细地介绍如何使用通用规则。

规则更新后你也应该更新占位符(图7中的项目1),如果你和图6比较,你会发现值从%54321.00%变成%54321%了,它更能代表zip代码,在这个特殊的例子中,元素的占位符和关联的规则的紧密相关的,假设它们自动相互跟踪是合理的,但在许多情况下,关系并不是直接的,元素和规则是多对多的关系:你可以对一个元素应用多个规则,或者一个规则应用给多个元素。

为了更新图7所示的元素占位符,在结构视图中//shipTo/zip字段上打开上下文菜单,选择‘编辑文本’,在对话框中将54321.00%修改成%54321%。

占位符为两个角色服务,CAM处理程序单独使用它确定某个元素的内容是否已被修复,这是由围绕在占位符两边的百分比符号确定的,注意在更新元素的占位符前,你要重新验证//shipTo/zip字段,确认在百分比符号中间的值被CAM处理程序忽略。

百分比符号之间的值应该是准确、简明地指出包含什么元素,通常上下文已经为你完成了大部分工作:元素的名字是‘zip’,在美国它会被立即认为是5、9或10位整数,通过设置占位符为%54321%,你告诉用户模板只接受5个字符的zip代码。

强度测试验证

现在你已经更新了占位符和规则,但只修改这两个地方就足够验证zip代码了吗?为了测试它,你需要为CAM处理程序提供不同的测试用例,最简单的方法是打开包含你要验证的数据的XML视图,修改//shipTo/zip的值,然后再重新验证,你可以在XML视图中象结构视图那样编辑节点:打开上下文菜单选择编辑文本,确定最小值以便覆盖到所有范围,让每个值都被验证一次,表3提供了这样一个列表,从这个表中可以看到有两个地方一个是pass掉,而另一个却没有过,只有这两个验证函数都过了才行。

//shipTo/zip setNumberMask(#####) setStringMask(00000)
90952 Pass Pass
90952.1 Fail Fail
123456 Fail Fail
90952-1234 Fail Fail
1 Pass Fail
(blank entry) Fail Fail
90952a Fail Fail
-12345 Pass Fail
(123) Fail Fail

表 3 zip代码测试用例:这个表显示了使用数字型特征码#####和使用字符串型特征码00000进行验证的结果,结果以绿色表示的是正确的,以红色表示的是错误的

这两个测试都通过具有相同的原因:特征码是数字,这两个测试都是有效的数字。虽然zip代码只包含数字,实际上它是一个字符串,从数字上来说,00001和1是相等的,在zip代码域中,00001代表一个有效的代码,而1不是。因此要使用numeric特征码代替textual特征码,为//shipTo/zip打开编辑约束对话框,将行为从setNumberMask修改成setStringMask,在String Mask字段上点击打开特征码编辑器,输入5个0,或者按数字0-9之间任何一个数字5次,然后退出这两个对话框,如果你现在重新验证表3中的每个测试用例,你会发现它们所有的测试结果都是正确的。

在正式的CAM规格说明书的3.4.3节(CAM内容特征码语法)列出了有效的特征码字符,表4就是改变自它的。

表 4 特征码字符:当规则行为需要特征码时,这些字符有特定的含义

字符 描述

字符串特征码

X 任何字符,强制性
A 强制性字母数字字符或空格
a 非强制性字母数字字符或空格
? 任何单一字符
* 0或更多字符0
U 一个可以被转换为大写的字符
^ 大写,非强制
L 一个可以被转换为小写的字符
_ 小写,非强制
0 数字、后缀和前端插入的0,前端插入的正负号
# 数字、后缀和前端插入的0被取消,前端插入的正负号
' ' 转义字符

数字型特征码

0 数字、后缀和前端插入的0,前端插入的正负号
# 数字、后缀和取消前端插入的0,前端插入的正负号
. 小数点
J 特征码的第一个字符,可能调用Java格式化方法处理特征码,当传递给Java时,文字J被忽略

日期型特征码

DD 一月中的某天
DDD 一年中的某天
DDDD 一月中的相对某天
MM 一年中的月份
MMM... 月名,如January(一月),字段会被填充或截断成3-10个数字
YY 两位数的年
YYYY 四位数的年
W 一周的某天
WWW... 期名,字段会被填充或截断成3-10个数字
/ 斜号,日期分隔符
- 连字符,另一个日期分隔符

如果你想找一个具有完整、清晰文档,并且所有的bug都被消除的工具,那这个可能会让你失望,但你如果不介意宝石周围那一点点瑕疵,我相信在你的兵器库中CAM会是一个伟大的工具,最后,我要告诉那些热心的开发者们,CAM编辑器和CAM引擎最近的版本(我用的是1.6.2版)中的行为完全是合理的。

这是第一部分的内容,到此就结束了,现在你至少知道其实使用CAM设计时还是很简单的,在本文的第二部分中,你将会看到CAM的强大之处,另外,你还将会看到关于开发模板和规则使用的技术更深入的讨论,包括:通用结构和通用规则,基于内部或外部因子的条件验证,详细比较XSD关于数据类型、排序和基数。最后还将介绍如何避免常犯的错误。

【编辑推荐】

  1. XML结构与语法入门详解
  2. XML新手入门 创建构造良好的XML
  3. 使用SAXParser处理XML文档
责任编辑:yangsai 来源: 51CTO.com
相关推荐

2017-12-12 16:43:54

SparkHadoop水平

2009-07-16 16:51:56

WebWork验证机制

2023-07-11 10:38:24

区块链文件验证安全

2012-02-02 15:04:02

软件开发

2012-06-21 16:19:30

程序员

2020-12-14 12:17:47

MySQL记录语句

2009-09-16 08:44:46

学习CCNA和CCNP

2022-06-01 14:10:46

物联网5G蜂窝技术

2010-09-07 16:34:47

DB2 XML

2022-03-24 15:11:49

区块链云计算数据

2009-01-04 16:58:48

LINQ to XMLLINQXML

2020-11-08 14:32:01

JavaScript变量内存管理

2010-10-29 10:56:46

ORACLE用户验证

2023-12-22 15:32:20

2011-08-11 11:08:09

2021-03-31 10:15:27

人工智能美国技术

2021-01-14 09:34:35

量子量子网络量子通信

2017-05-18 09:16:54

前端CSS技巧

2010-09-09 13:15:59

提高VPN质量

2010-01-04 10:34:01

Silverlight
点赞
收藏

51CTO技术栈公众号