从XML到Java代码的数据绑定之一 工具,无处不在的工具
副标题#e#
在这个由四部门构成的系列文章的第一部门,我们将弄清什么是数据绑定,与在 Java 应用措施中处理惩罚 XML 数据的其它要领对比它有什么优势,以及如何开始利用它。这一部门将观察为什么利用数据绑定,以及如作甚各类约束成立模子,使 XML 文档能转换成 Java 工具。同时还涵盖用于生成数据绑定类的输入和输出。
您但愿在您的 Java 应用措施中利用 XML 吗?那么好,同成千上万的其他人一起上这条船吧。当您深入相识 XML 今后,也许您会发明 DOM 和 SAX API(请参阅 参考资料)不外是唬人的对象。您大概认为 必定 存在某种简朴要领可以取得 XML 文档,并通过 Java 应用措施会见它,对吗? 不必通过回调或巨大的树状布局,而是利用像 setOwner(Stringowner) 和 int getNumOrders() 这样的要领,对吗?假如您曾经沿着这一思路思量问题,那么数据绑定就是您要寻找的办理方案。
阐明各类选择
当今各类 XML 和 XML 主义正泛滥成灾(XSL、RDF、定名空间、RSS、XML Schema、XSLT…),您大概认为此刻会有许多要领去会见 Java 应用措施中的 XML 数据。令人惊奇的是,假如您寻根究底,实际只存在三种会见 XML 数据的要领。没错 — 只有三种要领,个中的一种照旧最近随一种新的 Java API 才呈现的。
应该这样来对待这一问题:选择范畴小使您更易于选出适合于您的要领。
回调
回调是作为一种事件驱动模子事情的。当阐明 XML 文档时,某些事件 — 如文档的起始和某个元素中的字符数据的起始 — 将触发回调要领。通过利用执行逻辑所需的数据,您可以实现这些事件的 Java 代码。要弄清这种要领不能全靠直觉;开拓人员凡是要耗费一段时间来领略和把握回调模子的利用。SAX,用于 XML 的一种简朴 API,是这种 XML 利用要领的事实上的尺度。
树
更常见、更风行的是这种 API,它们取得一个 XML 文档,然后建设数据的树状布局。XML 文档成为树首,充当一种容器。它有若干子级,如根元素。根元素又有其附加的子级,依此类推,直到(在某种意义上)得到 XML 数据的一幅图为止。因为险些每个大学生在某个阶段必定都处理惩罚过树状布局,所以这就可用作暗示 XML 数据的一种很是直观的要领。
用于 XML 文档树状暗示的最风行的 API 就是 W3C 的推荐尺度,即文档工具模子 (DOM)。一种更新的 API,JDOM (这不是首字母缩写词)最近也正一直在推广并风行开来。 (固然这个方案是我和 Jason Hunter 成立的,但我还得说实话。)别的,DOM 和 JDOM 都是 Spinnaker 方案设计的根基要求,Spinnaker 是一种新的 XML 阐明器,它作为 Apache XML 方案的一部门正在开拓之中。
固然树状 API 看起来比事件驱动的 SAX 更易于利用,但它们并不老是符合的。很是大的文档大概需要大量的内存(尤其是利用 DOM 时);当对树布局执行转换 (XSLT) 时,系统大概遏制运转甚至彻底瓦解。 固然更新的 API(如 JDOM)能处理惩罚这些问题,但假如您必需处理惩罚极大量的数据,它们仍将是一个问题。而且,有时开拓人员甘愿将 XML 文档中的数据建模为一个简朴的带有值的读写要领的 Java 工具,而不消树状模子事情。譬喻,开拓人员会甘愿不去会见名为 skuNumber 的子节点并配置该节点的文本值,而只想挪用 setSkuNumber("mySKU") 并继承举办。
数据绑定
用 Java 代码会见 XML 数据的最新要领要依赖于一套新的 Java 要领和相关的 API,这些 API 仍在开拓之中。数据绑定是由 Sun 构建的一种“Java 类型要求”(JSR-031,见 参考资料),它设计用于使 Java 工具 绑定到 XML 文档越发利便,这样就使一种名目可以或许容易地转换为另一种名目,反之亦然。绑定引用一个具有读写要领的 Java 工具,读写要领城市影响到底层的 XML 文档,而且也都直接映射为 XML 文档中的元素及特征的名称。当您进入到本系列文章下一部门中的某些细节时,这一说明会更有意义,但在今朝,只说一点就够了:这样做使 XML 文档特征 name 可以或许通过一个称为 setName() 的要领,来变动它的值,就像我上面体现的那样。
这种会见方法正在获得普及,而且当在 XML 文档中存储设置信息时出格有用。很多开拓人员发明,它很是便于直接会见所需的参数,而无须利用更巨大的树状布局。固然这种会见对付文档转换或动静传送没有什么用处,但它对付简朴数据处理惩罚是极其利便的。它是我们在本文及本系列文章中存眷的第三种利用 XML 的要领。
(虽然,任何要领随后城市引出一系列新的术语,所以请查察 术语表明以相识这些新的行话。)
#p#分页标题#e#
是否任何 XML 文档都可以转换为 Java 工具?照旧仅有某些范例的 XML 文档才可以? 问得好!您很大概只但愿将满意一组约束条件的文档转换为 Java 工具。这与界说 Java 接口的要领雷同:您确保只实例化和利用适应该接口的工具,答允就如何操纵该工具作出假定。同样,您只答允将满意一组约束条件的 XML 工具转换成 Java 工具;这使您可以或许按但愿的方法来利用所建设的工具。
#p#副标题#e#
附:术语表明
数据绑定。从 Java 应用措施内部会见 XML 数据的一种新要领,利用仍在开拓中的一种 API,JSR-031。
JSR-031。Sun 仍在开拓中的一种新的 Java 类型请求,设计用于将 XML 文档编译成一个或多个 Java 类,而在 Java 应用措施中可以利便地利用这些 Java 类。
打包 。 将 Java 工具转换为 XML 暗示,拥有当前值。
解包 。 按照 XML 工具建设 Java 工具,凡是是按照打包生成一个 Java 工具。)
约束数据
在研究代码之前,您需要答复几个有关如何暗示 XML 数据的问题。这是数据绑定的最具挑战性的方面之一。是为每个文档建设一个新类,照旧建设某个现有类的一个实例?您要利用哪个现有类?而且最重要的是,您正在处理惩罚的文档是否适宜转换为 Java 工具?
那是一大堆问题,但您将在这里找到全部谜底。将这些问题看作一系列决定点,一系列选择。首先,您必需确定您可否从该 XML 文档建设 Java 工具(如前面所接头的那样)。假如能,您就要抉择转换应该以新 Java 类的形式呈现,照旧仅以现有类的一个实例的形式呈现。最后,假如选择了现有类,那么利用哪个类呢?功效就是各类百般的决定树。
假如我们考查清单 1 中所示的一个示例 XML 文档,然后再来处理惩罚这些问题,则决定树的意义就越发清楚了。此示例文档暗示 Enhydra Application Server 中某个处事(详细说就是一个 web 容器)的设置。
清单 1. 一个用于设置 Enhydra 中的 web 容器的 XML 文档
<?xml version="1.0"?>
<webServiceConfiguration
version="1.0"
name="My Web Container"
>
<port number="80"
protocol="http"
protected="false"
/>
<document root="/usr/local/enhydra/html"
index="*.html,*.xml"
error="error.html"
/>
</webServiceConfiguration>
此设置文档包括有关处事自己的版本和名称的信息,以及几个嵌套的项目,每个项目都暗示有关该 web 容器处事的一些附加信息。它给出了有关端口的具体信息(包罗端标语、协议和安详性),也给出了文档处事信息(包罗文档根、用于索引页的默认扩展名以及错误页)。所有这些合在一起,就是设置一个新的 web 容器处事所需的全部信息。
记着这个示例,您就可以开始答复数据暗示的各个问题了。
是否适合转换?
绝对适合!只要看一看 清单 1中的 XML 文档就会发明,它暗示一个工具(总体设置工具),具有若干特征或变量。个中某些变量又是别的的工具(端口和文档),这些工具又具有它们本身的特征。实际上,这是适合转换为 Java 工具的 XML 文档的一个极好例子。为了进一步担保此工具是可用的,稍后我将向您展示一种要领来约束文档中的数据。可是,照旧先让我们继承沿着决定树往下走。
转换成类照旧实例?
办理适宜性问题今后,此刻就可以作出抉择,是将每个 XML 设置文档都变为一个全新的 Java 类呢,照旧简朴地将其变为某个现有类的一个新实例。换句话说,就是到底应该生成新代码,照旧操作现有的代码。照这样来看,这就酿成了一个简朴的可重用性问题。更容易且更明智的做法是,为每个 XML 文档生成现有类的新实例。假如您 必然要实验一下从每个文档建设一个新的 Java 类,则获得的各个类之间大概没有兼容性 — 即两个完全沟通的文档大概导致两个差异的 Java 类!
不消这个大概引起杂乱的要领,您可以回收一组 XML 约束条件(由一个 DTD 或 XML 方案暗示,将在下面报告),并按照这些约束条件来生成一个 Java 类(或多个类,按照需要)。这个生成的类将暗示切合这些约束条件的任何 XML 文档;这些 XML 文档中的每一个都将被解包到生成的类的一个实例中。在这种环境下,就可觉得暗示 web 处事设置的文档界说约束条件。 这些约束条件将被映射为一个 Java 类,我们将称之为 WebServiceConfiguration 。 然后您就可以得到任何一种暗示特定 web 处事设置的 XML 文档,并假定此文档切合我们的约束条件,由它而建设出前面生成的类的一个实例。这将答允应用措施将差异的 XML 文档用作沟通范例的工具,只要这些文档中的数据对付该工具设计时要到达目标来说是有效的即可。
新类照旧现有的类?
#p#分页标题#e#
此刻您也已经有条件答复下一个问题了:您但愿建设一个现有类即 WebServiceConfiguration 类的一个实例。剩下需要弄清的全部工作是,这个类是如何预先生成的。 所以,此刻请将您的留意力会合在这样一个问题上:如何得到一组约束条件,用 XML 实现它们,并担保文档切合这些约束?再一个问题就是,您如何再从这些约束条件生成一个可重用的 Java 类?
操作文档约束条件
既然您知道此文档将转换成一个 Java 实例,这就发生了另一个问题:要思量到必需以某种方法担保可将此文档正确地解包到一个选定的 Java 类中。缺少变量或数据范例不正确都大概导致在解包进程中堕落 — 可能甚至在客户时机见设置错误的容器时呈现运行时异常。
最好的环境是,在实际的解包进程开始之前,文档的作者可以或许担保,设置文档对付他们选择用来暗示数据的类是“正当的”。阅读到这一方案的 XML 人士说不定就会动弹他们的眼睛并嘀咕说,“好吧,虽然您将利用 XML 文档约束条件。”确认数据对选定类的正当性可以通过引用 DTD (文档范例界说)或 XML 方案来完成。
通过利用一组用外部 DTD 或方案文件暗示的约束条件,文档作者就可以在这些数据的“接口”上测试设置数据。换句话说,您可以这样来成立应用措施,使之可以或许比较所需的数据来查抄包括在 XML 实例文档中的数据,而所需数据则是在文档约束条件的外部文件中指定的。 这样,您就可觉得数据建设一个接口。
在利用 DTD 方案照旧利用 XML 方案之间作出决定是一种相当简朴的选择:因为 Java 语言是高度范例化的,所以我们但愿能在 XML 文档中支持范例化。譬喻,数据接口应该可以或许验证,为 web 容器的端标语提供的是整数,而不是字符串,后者在处事启动时将引起错误。DTD 不支持范例查抄,所以我们无疑应该选择 XML 方案。固然 XML 方案在类型的规模在有一点不确定性,但它在很洪流平上已趋于不变,并可望在年内定型。我们可以在一个 XML 方案中编写数据约束条件,然后用这个方案验证大概的实例文档,以确保解包能在这些实例文档长举办。下面的 XML 方案暗示我们的 web 容器处事的数据接口。
清单 2. 暗示一个 web 容器设置文档的数据接口的 XML 方案
<?xml version="1.0"?>
<schema targetNamespace="http://www.enhydra.org"
xmlns="http://www.w3.org/1999/xmlSchema"
xmlns:enhydra="http://www.enhydra.org"
>
<complexType name="ServiceConfiguration">
<attribute name="name" type="string" />
<attribute name="version" type="float" />
</complexType>
<element name="serviceConfiguration" type="ServiceConfiguration" />
<complexType name="WebServiceConfiguration"
baseType="ServiceConfiguration"
derivedBy="extension">
<element name="port">
<complexType>
<attribute name="protocol" type="string" />
<attribute name="number" type="integer" />
<attribute name="protected" type="string" />
</complexType>
</element>
<element name="document">
<complexType>
<attribute name="root" type="string" />
<attribute name="index" type="string" />
<attribute name="error" type="string" />
</complexType>
</element>
</complexType>
<element name="webServiceConfiguration" type="WebServiceConfiguration" />
</schema>
清单 2 中的 XML 方案界说了几个差异的数据工具,它们合起来暗示一个 web 处事的设置工具。首先,界说了一个焦点处事设置( serviceConfiguration ),它包括版本和名称。这可用作所有处事(如负载平衡处事、EJB 容器,虽然尚有我们的 web 处事)的根基工具。然后,作为此根基处事的扩展,又界说了 web 处事设置( webServiceConfiguration )。请留意,Java 成型之后,方案就已经为数据接口成立了模子。我们将附加的 web 处事属性 port 和 document 添加到 version 和 name 根基属性中。这些属性自己都是工具,具有它们本身的属性( protocol 、 root 、 error 等)。
#p#分页标题#e#
在此方案的界说方法中,特征代表简朴的 Java 范例,凡是是原始 (primitive) 范例。这样, name 和 version 就别离成为范例 String 和 float 的 Java 原始范例。 port 和 document 这样的元素成为 Java 工具,它们可以有本身的属性,照旧用特征来暗示。 这样就呈现了递归现象:元素酿成新工具,并对它的每个属性举办查抄。假如属性是一个特征,就为此工具建设一个简朴的 Java 原始成员变量;假如属性是元素,则建设一个新的工具,并作为一个成员变量将其添加,然后在这个新工具上又开始同样的进程,直到全部类都已建设为止。
从萝卜 … 嗯 … XML 得到 Java
一旦建设了 XML 方案,您就需要从这个方案中提取出必须的信息,来确定应该建设哪些 Java 类。这个进程的第一步是查察 XML 方案,并严格确定输出应该是什么。对付简朴的 serviceConfiguration 工具,界说了两个 Java 原始属性: name 和 version 。 对付这样一个简朴的工具,确定所需的接口并不难。 只需将被界说范例的名称的首字母大写,并将这些 Java 属性添加到接口中即可,如清单 3 所示。
清单 3. 为 ServiceConfiguration 接口而从 XML 方案生成的 Java 代码
public interface ServiceConfiguration {
public void setVersion(float version);
public float getVersion();
public void setName(String name);
public String getName();
}
这是相当大白易懂的; 清单 3中的接口为 XML 方案中界说的属性提供读要领和写要领。别的,您将需要生成一个实现类来界说此接口的各个成员变量,并实现此接口中的每个要领。这种使接口从实现中疏散出来的要领使我们可以或许为特定的需要提中供多种实现。 譬喻,某个特定的处事大概需要执行计较,而不可是接管从写要领中收到的值。 此刻思量那种更巨大的环境尚有点为时尚早,但我将在后续文章中从头提到它。然而,一般说来,您仍可以确定实现类应该像什么样子,如清单 4 所示。
清单 4. 为 ServiceConfiguration 实现而从 XML 方案生成的 Java 代码
public class ServiceConfigurationImpl implements ServiceConfiguration {
private String name;
private float version;
public void setVersion(float version) {
this.version = version;
}
public float getVersion() {
return version;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
沟通的原则也合用于 XML 方案中界说的其它工具。您可以在下面查察到其它 Java 类(因为它们都是应该生成的):
PortType.java (文章开始的源代码包中附源码)
PortTypeImpl.java (文章开始的源代码包中附源码)
DocumentType.java (文章开始的源代码包中附源码)
DocumentTypeImpl.java (文章开始的源代码包中附源码)
WebServiceConfiguration.java (文章开始的源代码包中附源码)
WebServiceConfigurationImpl.java (文章开始的源代码包中附源码)
总结
到今朝为止,您应该对数据绑定的各个方面都较量熟悉了。 我已劈头先容了您应该利用数据绑定的原因,尤其是在设置信息的范畴内,并概述了为实现此要领您所需要相识的一些根基观念。
此系列文章的下一篇将继承考查数据绑定的进程。您将有时机去查抄 org.enhydra.xml.binding.SchemaMapper 类,它将接管这第一部门中建设的 XML 方案作为数据接口,并从它建设出一个 Java 接口和实现类。本系列文章的第二部门将具体说明这一进程的每个步调,并说明如何确保方案被精确暗示,以便 XML 文档能接着被转换为生成的类的实例。
梳理一下您学到的 XML 方案和 JDOM (我将在示例代码中利用它们),下个月再见!
本文配套源码