本文引用地址为:http://www-128.ibm.com/developerworks/cn/xml/x-beans1/index.html?ca=dwcn-newsletter-xml
随着企业应用程序的复杂性不断加剧,XML 文档的约束和规则变得越来越严格。此外,随着业界越来越迅速地采用 Web 服务,XML 开始成为跨越多种平台的不可忽视的重要角色。所有这一切意味着,应用程序迫切需要一种简单而强大的机制来处理 XML。
XMLBeans 提供了这样一种机制,可以将 XMLBeans 用于 XML 数据绑定。与其他只支持 W3C XML Schema 规范的某个子集的数据绑定技术不同,XMLBeans 支持完整的规范,从这方面来说,它非常强大。对于习惯于面向对象操作的开发人员来说,它还惊人地易用。
通过 XMLBeans,您可以使用 Java 类访问和操纵 XML 文档中包含的数据。
它是如何做到这些的呢?实际上,它包括两个步骤:
一旦 XMLBeans 编译器生成了和模式对应的一般 Java 类和接口,任何符合该模式的 XML 实例文档都可以使用这些类和接口绑定。XMLBeans 比传统的解析更进了一步,因为用户不再需要进行以下操作:
这是一个简单的例子:输入一个模式,XMLBeans 编译器会将其编译成通用的接口。然后我会向您展示如何将符合该模式的具体 XML 文档实例绑定到这些接口。
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="automobile-policy"> <xs:complexType> <xs:sequence> <xs:element name="insurance-date" type="xs:dateTime"/> <xs:element name="policyholder-information" type="policyholder-information" minOccurs="1"/> <xs:element name="insured-vehicle" type="insured-vehicle" minOccurs="1"/> <xs:element name="liability-coverage" type="liability-coverage" minOccurs="1"/> <xs:element name="third-party-coverage" type="third-party-coverage"/> </xs:sequence> </xs:complexType> </xs:element> <xs:complexType name="policyholder-information"> <xs:sequence> <xs:element name="name" type="xs:string"/> <xs:element name="social-security-number" type="xs:string"/> <xs:element name="address" type="xs:string"/> </xs:sequence> </xs:complexType> <xs:complexType name="insured-vehicle"> <xs:sequence> <xs:element name="year-of-manufacture" type="xs:string"/> <xs:element name="make" type="xs:string"/> <xs:element name="model" type="xs:string"/> <xs:element name="price" type="xs:double"/> </xs:sequence> </xs:complexType> <xs:complexType name="liability-coverage"> <xs:sequence> <xs:element name="coverage-limit" type="xs:double"/> <xs:element name="coverage-premium" type="xs:double"/> </xs:sequence> </xs:complexType> <xs:complexType name="third-party-coverage"> <xs:sequence> <xs:element name="coverage-limit" type="xs:double"/> <xs:element name="coverage-premium" type="xs:double"/> </xs:sequence> </xs:complexType> </xs:schema> |
清单 1中的模式描述的是一种汽车保险单,其中包括:
在进入 清单 1所示模式的编译过程之前,请下载并安装 Apache XMLBeans version 1.03(请参阅 Resources)。释放压缩包中的文件,将 bin 目录放到 path 下,并将 lib/xbean.jar 放到 classpath 中。
bin 目录中包含执行一些有用动作的脚本,比如(在 Windows 平台上):
对于 UNIX 和 Linux 平台,XMLBeans 提供了 scomp.sh 和 validate.sh 来执行上述操作。
xbean.jar 包含真正的 XMLBeans API 类。
将模式放在适当的文件夹中并设置好 path 与 classpath ,使用 下面的命令编译模式:
scomp -out automobile-policy.jar automobile-policy.xsd |
在上述命令中, scomp 是模式编译器, -out 选项用于命名输出的 jar 文件,这里使用的 automobile-policy.jar ; automobile-policy.xsd 是编译的模式。
上述命令将 automobile-policy.xsd 编译成 XMLBeans 接口和类,并将它们打包到 automobile-policy.jar 。编译后将生成以下接口:
生成的接口包名是从模式中使用名称空间衍生出来的。因为该模式没有包含名称空间,所以这些接口将被放在包 noNamespace 中。
让我们看一看这些接口。 AutomobilePolicyDocument 接口包含以下方法:
与此类似, AutomobilePolicyDocument$AutomobilePolicy 接口也包含以下方法:
其中的关键是将 XML Schema 结构作为 Java 接口复制,所有的基本操作,即添加新元素以及访问、设置已有的元素,都是作为这些接口的方法来实现的。
此外,所有生成的接口都有一个包含静态方法的工厂类,比如:
将模式编译成 XMLBeans 接口和类之后,需要将 XML 实例绑定到这些类。下面的代码取自 AutomobilePolicyHandler.java ,它使用生成的接口,根据编译后的模式处理真正的 XML 实例。
import noNamespace.*; import java.io.File; import java.util.Calendar; public class AutomobilePolicyHandler{ public static void main(String args[]) { try { String filePath = "automobile-policy.xml"; java.io.File inputXMLFile = new java.io.File(filePath); AutomobilePolicyDocument autoPolicyDoc = AutomobilePolicyDocument.Factory.parse(inputXMLFile); AutomobilePolicyDocument.AutomobilePolicy autoPolicyElement = autoPolicyDoc.getAutomobilePolicy(); System.out.println("date is " + autoPolicyElement.getInsuranceDate()); } catch (Exception e) { e.printStackTrace(); } } } |
清单 2 的代码接受输入的 XML 实例,并使用 AutomobilePolicyDocument Factory 类的 parse() 方法获得 AutomobilePolicyDocument 实例。
上述 AutomobilePolicyDocument 实例的 getAutomobilePolicy() 方法可以提供根元素 automobile-policy 的句柄。您可以使用简单的 getter 和 setter 检索 XML 中子元素的值。
下面的 XML 文件 automobile-policy.xml 符合模式 automobile-policy.xsd ,可以将它用于 清单 2中的方法。
<automobile-policy> <insurance-date>2004-09-05T14:12:22-05:00</insurance-date> <policyholder-information> <name>Alan</name> <social-security-number>1GBL7D1G3GV100770 </social-security-number> <address>171 Dormonth Street, Fairfield, OH</address> </policyholder-information> <insured-vehicle> <year-of-manufacture>1999</year-of-manufacture> <make>Chevy</make> <model>Optra</model> <price>1234</price> </insured-vehicle> <liability-coverage> <coverage-limit>1222</coverage-limit> <coverage-premium>12</coverage-premium> </liability-coverage> <third-party-coverage> <coverage-limit>2343</coverage-limit> <coverage-premium>14</coverage-premium> </third-party-coverage> </automobile-policy> |
编译生成的所有 XMLBeans 类都是从 org.apache.xmlbeans.XmlObject 派生的。这是所有 XMLBeans 类型的基本接口,包含一些所有 XMLBeans 类都提供的通用设施:
在 XMLObject 层内,有用户驱动的模式类型和内置模式类型。我已经说明了用户驱动类型(如 automobile-policy 和 policyholder-information )的语义。如前所述,每个用户驱动的模式类型都被表示成一个接口。
另一方面,对于 xs:int 和 xs:string 这类内置模式类型,XMLBeans 提供了 46 种 Java 类型,对应于 W3C XML Schema 规范定义的 46 种内置类型。比如,为了对应 XML Schema 中的 xs:string ,XMLBeans 提供了 XmlString 。
让我们再回到模式,为了提取 policyholder-information 复杂类型中的 xs:string 类型的社会安全号,XMLBeans 提供了以下方法:
org.apache.xmlbeans.XmlString xgetSocialSecurityNumber(); |
该方法返回 XmlString 。
当然,XMLBeans 也提供了返回纯 Java 类型的方法:
java.lang.String getSocialSecurityNumber(); |
注意,在返回 XMLBeans 类型的情况下,方法名是以 xget 开头的。 xget 版本的方法在性能上要好于 get 版本,因为 get 需要将数据转化成最适当的 Java 类型。
通过这个简单的例子,您已经发现使用 XMLBeans 是多么容易,而且也熟悉了 XMLBeans 的层次结构,现在来看一看 XMLBeans 的一些高级特性。这些特性才真正代表了 XMLBeans 的强大功能。
XML 游标定义了 XML 文档中的一个位置。它最适合没有可用模式的 XML 文档。游标允许用户通过改变自身的位置来遍历整个文档,还允许用户删除和插入 XML 片段,访问和设置 XML 值等。
清单 4 是一个简单的例子,说明了 XML 游标的用法。 CursorHandler.java 中的代码将检索 automobile-policy.xml 中已保险汽车的型号。
import noNamespace.*; import java.io.File; import java.util.Calendar; import org.apache.xmlbeans.XmlCursor; public class CursorHandler { public static void main(String args[]) { try { String filePath = "automobile-policy.xml"; java.io.File inputXMLFile = new java.io.File(filePath); AutomobilePolicyDocument autoPolicyDoc = AutomobilePolicyDocument.Factory.parse(inputXMLFile); XmlCursor cursor = autoPolicyDoc.newCursor(); cursor.toFirstContentToken(); cursor.toChild(2); cursor.toChild(2); System.out.println(cursor.getTextValue()); System.out.println("Type of Token is: " + cursor.currentTokenType() + "\nText of Token is" + cursor.xmlText()); cursor.dispose(); } catch (Exception e) { e.printStackTrace(); } } } |
该例中的游标被定义在 XML 实例的开头。方法 toFirstContentToken() 将游标移动到当前 START 或 STARTDOC 内容中的第一个标志上。从本质上说,这意味着将游标移到了根元素 automobile-policy 的起始位置上。
因此, cursor.getTextValue() 将打印 XML 文档的全部内容。
因为我们的目的是查找已保险汽车的型号, cursor.toChild(2) 方法将游标移动到 automobile-policy 的第三个子元素,即 <insured-vehicle> 。现在游标移到了 <insured-vehicle> 元素上,再次调用 cursor.toChild(2) 方法可以将游标移动到相对于当前位置的第三个子元素上,即 <model> 元素。
然后用方法 cursor.getTextValue() 检索型号值。
在完成游标的使用之后,不要忘记调用其 dispose() 方法。
XML 标志代表一类 XML 标记。实际上,XML 标志代表了 XML 文档能够包含的不同类型的部分。其中包括 XML 文档的开始和结束、属性和属性值等。
在代码中移动 XML 游标时,可以将它从一个标志移动到另一个标志。当您移动游标时,是将它移动到符合要求的标志。如果游标没有发现可以移动到的适当标志,那么它将保留在原位,并返回“false”表示游标没有移动。
每种标志类型都用 TokenType 类中的一个常数表示,其中包括:
标志本身不作为对象公开,但其类型和属性可以通过游标方法来访问。比如, CursorHandler.java 中的下列代码片段将打印标志类型和标志值。
System.out.println("Type of Token is: " + cursor.currentTokenType() + "\nText of Token is" + cursor.xmlText()); |
XMLBeans 支持 XQuery 表达式。这种类 SQL 语法能够遍历 XML 文档来访问元素和属性。XQuery 表达式和 XML 游标的结合大大增强了 XQuery 的能力。我们仍然使用上述从 automobile-policy.xml 中检索已保险车辆型号的例子,清单 6 中的代码片段就能够完成这项工作。
XmlCursor cursor = autoPolicyDoc.newCursor(); String modelQuery = $this/automobile-policy/insured-vehicle/model; //Note that execQuery creates a new cursor XMLCursor resultCursor = cursor.execQuery(modelQuery); System.out.println(resultCursor.getTextValue()); |
|
清单 6 中的代码创建了一个到达所需元素的 XQuery 表达式。 execQuery() 方法运行该查询表达式,并返回新的 resultCursor 。然后使用该 resultCursor 打印 model 元素的值。变量 $this 表示 XML 游标的当前位置。
|
XMLBeans 面临着传统解析和绑定技术的竞争,如 DOM、SAX、JAXB 和 Castor,但 XMLBeans 有一些独到之处。它们的比较如下:
在 XML 和 Java 技术的发展前沿地带,各种各样的技术互相拥挤碰撞着,XMLBeans 在非常短的时间内站稳了脚跟。如果开发人员需要处理复杂的 XML 模式和需要更多的本机支持(比如访问完整的 XML Infoset),那么 XMLBeans 是无可替代的。
性能的优势和即时验证支持,使 XMLBeans 成为用于各种 XML 和 Java 数据绑定场景的一种非常强大的工具。易于理解的 API 降低了开发人员的学习难度,也使其成为非常诱人的选择。这是一项强大而激动人心的技术。