Java SE 6 做为一个开发平台,针对不同的应用开发需求,提供了各种各样的技术框架。XML 处理框架是 JDK 6
的重要组成部分之一。它为应用程序开发人员提供了一个统一的 XML 处理
API。这种框架结构有两个作用:一方面,开发人员透过这些框架,可以透明的替换不同厂商提供的 XML
处理服务;另一方面,服务提供商可以透过这些框架,将自己的产品插入到 JDK 中。这种框架一般被称为 Service Provider
机制。Java SE 6 的 XML 处理功能分为两个部分:XML 处理(JAXP)和 XML 绑定(JAXB)。在 XML
处理框架之上,Java SE 6 结合了注释(Annotation)技术,提供了强大的针对 Web 服务的支持。
本
文首先介绍 Service Provider 机制及其在 XML 框架中的应用。然后介绍 Java SE 6 中 XML 框架的功能,包括
SAX,StAX,DOM 三种机制。最后介绍在此基础之上构建 Web 服务的技术。JAXB 和 Web 服务的开发关系紧密,故 JAXB
的介绍也放在 Web 服务部分介绍。本文内容基于 Java SE 6 SDK。
Service Provider 机制
对
于同一个功能,不同的厂家会提供不同的产品,比如不同品牌的轮胎、插头等。在软件行业,情况也是如此。比如,对于数据的加密解密,不同的厂家使用不同的算
法,提供强度各异的不同软件包。应用软件根据不同的开发需求,往往需要使用不同的软件包。每次更换不同的软件包,都会重复以下过程:更改应用软件代码
-> 重新编译 -> 测试 ->
部署。这种做法一般被称为开发时绑定。这其实是一种比较原始的做法,缺乏灵活性和开放性。于是应用运行时绑定服务提供者的做法流行开来。具体做法是,使用
配置文件指定,然后在运行时载入具体实现。Java SE 平台提供的 Service Provider
机制是折衷了开发时绑定和运行时绑定两种方式,很好的满足了高效和开放两个要求。
构成一个 Service Provider 框架需要大致三个部分,图 1 给出了一个典型的 Service Provider 组件结构。Java SE 平台的大部分 Service Provider 框架都提供了 3 个主要个组件:面向开发者的 Application 接口,面向服务提供商的 Service Provider 接口和真正的服务提供者。
图 1. Service Provider 的组件结构
这样做的主要好处包括:
提供了供应商的中立性,应用代码与服务提供商完全独立,互不依赖。应用程序开发者针对 图 1 中 Application 接口进行开发。这个接口将不同提供商的接口差异性屏蔽掉了。无论使用哪个厂商的服务,应用程序都是针对一个稳定、统一的接口开发,业务逻辑和第三方组件之间有很强的独立性。如果有需要,应用程序可以针对不同提供商重新部署。清单 1 显示某应用程序中的一段代码。
清单 1. 通过统一应用程序接口获得服务
SAXParserFactory factory = SAXParserFactory.newInstance();
System.out.println(factory.getClass());
// Parse the input
SAXParser saxParser = factory.newSAXParser();
System.out.println(saxParser.getClass());
Output: class org.apache.xerces.jaxp.SAXParserFactoryImpl
Output: class org.apache.xerces.jaxp.SAXParserImpl
-
本例中 saxParser 的类型被声明为 SAXParser,但实际类型如 清单 1 中显示,为 org.apache.xerces.jaxp.SAXParserImpl。实际类型是由 SAXParserFactory 的静态方法 newInstance 查找配置文件,并实例化得到的。图 2 展示了 Java SE 6 中 XML 包的 Service Provider 的交互细节。请参考 Apache Harmony 项目的具体代码(参见 参考资源)。
图 2. XML 包的 Service Provider 结构
-
提供了扩展性,更多的服务可以加入开发平台;为了便于不同的开发商开发各自的产品,Java SE 平台同时为服务提供商设计了统一的接口。只要提供者满足这些接口定义(比如继承某个接口,或者扩展抽象类),服务提供者就能被添加到 Java SE 平台中来。以 图 2 给出的结构为例,服务提供者需要继承 SAXParserFactory、SAXParser 等抽象类,同时将类 VendorSaxParserFactoryImpl 的名字注册到 jaxp.properties 文件中,就可以被使用了。
-
兼
顾了灵活性和效率。通过这种方式,一方面组件提供者和应用开发者开发时绑定到一个约定的接口上,另一方面载入具体哪个组件则是在运行时动态决定的。不同于
Web 服务等技术的完全动态绑定(通过运行时解析 WSDL
文件来决定调用的类型),也不是完全的编码时绑定,这种折衷的方式提供了松耦合、高扩展性,同时也保证了可接受的效率。
XML 框架介绍
Java
SE 6 平台提供的 XML 处理主要包括两个功能:XML 处理(JAXP,Java Architecture XML
Processing)和 XML 绑定(JAXB,Java Architecture XML Binding)。JAXP 包括 SAX 框架
—— 遍历元素,做出处理;DOM 框架 —— 构造 XML 文件的树形表示;StAX 框架 —— 拖拽方式的解析;XSLT 框架 —— 将
XML 数据转换成其他格式。JAXB 则是负责将 XML 文件和 Java 对象绑定,在新版 JDK 中,被大量的使用在 Web 服务技术中。
SAX 框架(Simple API for XML)
SAX 全称 Simple API for XML,该框架使用了事件处理机制来处理 XML 文件,图 3 展示了这个过程。
图 3. SAX 框架处理 XML 文件的流程
SAXParser 将 XML 文件当作流读入。当 parser 遇到 Element_A,就会产生一个事件,然后将该事件发送给处理类。SAX 框架的一大特点是对于节点的处理是上下文无关的。比如 图 3 中 SAXParser,允许注册一个处理类,这个处理类对于所有节点并不加以区分,对他们的处理过程都是一致的。一般包括 startElement 和 endElement 等动作。清单 2 给出了处理类的 startElement 动作的伪代码。
清单 2. 处理类的 startElement 动作的伪代码
1 CLASS Listener < DefaultListener
2 PROCEDURE StartElement(…)
3 IF ( node->Obj.name == ‘Node’ )
4 // Do some calculation
5 FI
6 END
7 END
8 SAXParser->SetListener(new Listener)
使用 SAX 框架,对于 Node 节点的处理并不会根据其前驱或者后缀节点的不同而有所区别。伪代码 3-5 行说明了这一点。一旦发现节点名称是 Node,则进行预定的处理。这个框架本身并不支持对节点进行上下文相关的处理,除非开发者另外维护一些数据结构来记录上下文状态。正是由于 SAX 框架不需要记录的状态信息,所以运行时,SAX 框架占用的内存(footprint)比较小,解析的速度也比较快。
DOM 框架(Document Object Model)
DOM
框架的全称是 Document Object
Model。顾名思义,这个框架会建立一个对象模型。针对每个节点,以及节点之间的关系在内存中生成一个树形结构。这个特点与 SAX
框架截然相反。需要注意的是,DOM 框架提供的对象树模型与我们通常理解的 XML 文件结构树模型是有一定的区别的。图 4 给出了一个 XML 文件的结构。
图 4. DOM 框架的对象模型
图 4 中的 Element_B 具有 清单 3 这样的结构:
清单 3. Element_B 的 XML 结构
<Element_B>This is start of Element_B
<Node>…</Node>
This is end of Element_B
</Element_B>
按照 图 4 和 清单 3 给出的结构,一般的对象的观点理解,Element_B 包含子元素 Node,而两句话”This is start of Element_B”与”This is end of Element_B”是 Element_B 节点的内容。而实际上,当针对 Element_B 调用 Element.getContent,得到的是 Element_B 这个名字本身,两句文本同 Node 一样,也是作为子节点的。可以这样认为,DOM 的对象模型,在内存中模拟的是 XML 文件的物理存储结构,而不是节点间的逻辑关系。DOM 中结点的类型也是通过 getContent 返回的节点名字符串区别的。当客户端识别节点类型时,通常会形成以下的代码片断:
清单 4. 使用 DOM 框架的客户端代码
name = Element.getContent
SWITCH name
CASE Element_A:
// Do something
BREAK
CASE Element_B:
// Do something
BREAK
DEFAULT:
END
这种方式是很明显的早绑定 —— 编码时 / 编译时绑定,而不是面向对象语言中使用的运行时绑定技术 —— 继承带来的虚拟函数特性。这个问题的产生和 DOM 框架的设计目标有关。DOM 的目标是一个编程语言无关的,用来处理大段复杂 XML 文件的框架(参见 参考资源),
比如书籍和文章。DOM 框架一个显著的特征是善于处理节点与文本混合的 XML 文件(Mixed-Content Model)。这种设计使得
XML
形成树的过程是一个直接映射,不需要进行概念上的转换,也就节省掉很多的处理细节,一定程度上提高了效率。这一点在处理大文件时比较明显,兼顾了效率和上
下文状态问题。另一方面,由于编程语言无关的设计目标,也决定了放弃虚函数机制是必要的。
StAX 框架(Streaming API for XML)
SAX
框架的缺点是不能记录正在处理元素的上下文。但是优点是运行时占内存空间比较小,效率高。DOM 框架由于在处理 XML
时需要为其构造一棵树,所以特点正好相反。StAX 框架出现于 Java SE 6 中,它的设计目标就是要结合 SAX 框架和 DOM
框架的优点。既要求运行时效率,也要求保持元素的上下文状态。清单 5 是一段使用 StAX 框架处理 XML 文件的代码。
清单 5. 使用 StAX 框架处理 XML 文件
import java.io.*;
import javax.xml.stream.*;
import javax.xml.stream.events.*;
public class StAXTest {
public static void main(String[] args) {
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
InputStream input = new ByteArrayInputStream(
("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<work-contact-info>" +
"<Location>Shanghai-shuion-333</Location>" +
"<Postal>200020</Postal>" +
"<Tel><fix>63262299</fix><mobile>1581344454</mobile></Tel>" +
"<Appellation>Mr. Wang</Appellation>" +
"</work-contact-info>").getBytes());
try {
XMLEventReader xmlEventReader = inputFactory.createXMLEventReader(input);
while (xmlEventReader.hasNext()) {
XMLEvent event = xmlEventReader.nextEvent();
if (event.isStartElement()) {
StartElement startElement = event.asStartElement();
System.out.println(startElement.getName().toString());
}
if (event.isCharacters()) {
Characters text = event.asCharacters();
if (!text.isWhiteSpace()) {
System.out.println("\t" + text.getData());
}
}
}
} catch (XMLStreamException e) {
e.printStackTrace();
}
}
}
观察后可以发现 StAX 框架和 SAX 框架具有相似的地方。StAX 有 Event.isStartElement 方法,SAX 有 DefaultHandler.startElement 方法。StAX 有 Event.isCharacter 方法,SAX 有 DefaultHandler.character 方法。实际上这两个框架处理 XML 文件的时候使用了相似的模型——将 XML 文件作为元素组成的流,而不同于 DOM 的树模型。解析 XML 文件时,应用程序调用 XMLEventReader 的 nextEvent 方法解析下一个元素(或者是解析同一个元素,根据解析的不同阶段,产生不同元素),StAX 就会通过 XMLEventReader 产生一个事件。比如针对同一个元素,可能会产生 StartElement 和 EndElement 事件。形象的说 XMLEventReader 就像是一根绳子,拽一下,解析一个元素,产生一个事件。于是这种技术也被称为”Pull Parser”技术。StAX 在处理 XML 文件时,产生的所有事件是通过一个 Iterator(XMLEventReader 继承了 Iterator)返回的。应用程序通过这个 Iterator 能知道某个解析事件的前后分别是什么。这类信息就是一个元素的上下文信息。
XSLT 数据转换框架(The Extensible Stylesheet Language Transformations APIs)
一
般来说 XML 文件格式被认为是一种很好的数据交换格式。于是 Java SE 6 SDK 基于以上介绍的三种 XML 处理机制,提供了一个
XML 转换框架。XSLT 框架负责进行转换 —— 包括将 XML 文件转换成其他形式如 HTML,和将其他形式的文件转换成 XML
文件。更进一步说,这个框架可以接受 DOM 作为其输入和输出;可以接受 SAX 解析器作为输入或者产生 SAX 事件作为输出;可以接受 I/O
Stream 作为输入和输出;当然也支持用户自定义形式的输入和输出。图 5 显示了这种依赖关系:
图 5. XSLT 框架的依赖关系
转换框架的输入输出对象的类型并不要求是一一对应的。比如,使用 DOMSource 做为输入,可以使用 StreamResult 作为输出。清单 5 是一段伪代码,用来显示 JDK 将不同 javax.xml.transform.Source 转换成不同 javax.xml.transform.Result 子类型的过程:
清单 5. JDK 转换框架的转换过程
// Construct input
1. factory = XMLParserDocumentFactory->NEW
2. parser = factory->NewParser
3. document = parser->Parse(File)
// Wrap input/output
4. source = Source->NEW( document )
5. sink = Result->NEW
// Construct transformer
6. tFactory = TransformerFactory->NEW
7. transformer = tFactory->NewTransformer
// Transform
8. transformer->Transfer( source, sink)
通过这个过程的转化,一个 javax.xml.transform.Source 可以转化成为类型 javax.xml.transform.Result。JDK 提供了如 图 5 所示的 4 种 Result 子类型,用户也可以定义自己的 Result 类型。另一方面,用户自定义的数据解析器或者数据文件,也可以作为 Transformer 的输入。下面一个例子,针对一个数据文件,首先生成了一棵 DOM 树,然后又根据这棵 DOM 树,提取了所有的联系信息,生成了一个文本文件。清单 6 给出了这个数据文件:
清单 6. 地址信息文件
work contact-info
Location Shanghai-shuion-333
Postal 200020
Tel
fix 63262299
mobile 1581344454
Appellation Mr. Wang
清单 7 为这个信息文件构造一个 DOM 树,并将其作为 transformer 的输入。
清单 7. 构造 DOM 树
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
class ContentHandler extends DefaultHandler {
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
String name = new String(ch, start, length);
System.out.print(name + "\t");
}
}
public class DOMTest {
/**
* @param args
* @throws TransformerException
*/
public static void main(String[] args) {
try {
DocumentBuilderFactory documentfactory = DocumentBuilderFactory
.newInstance();
DocumentBuilder builder = documentfactory.newDocumentBuilder();
Document document = builder.newDocument();
Element root = document.createElement("work-contact-info");
Element loca = document.createElement("Location");
loca.setTextContent("Shanghai-shuion-333");
root.appendChild(loca);
Element postal = document.createElement("Postal");
postal.setTextContent("200020");
root.appendChild(postal);
Element tel = document.createElement("Tel");
root.appendChild(tel);
Element fix = document.createElement("fix");
fix.setTextContent("63262299");
tel.appendChild(fix);
Element mobile = document.createElement("mobile");
mobile.setTextContent("1581344454");
tel.appendChild(mobile);
Element appellation = document.createElement("Appellation");
appellation.setTextContent("Mr. Wang");
root.appendChild(appellation);
document.appendChild(root);
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer;
transformer = tFactory.newTransformer();
SAXResult result = new SAXResult();
ContentHandler cHandler = new ContentHandler();
result.setHandler(cHandler);
transformer.transform(new DOMSource(document), result);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Java SE 6 SDK 提供了至少以上三种内置的处理 XML 文件的机制。它们分别是 Simple API for
XML、Document Object Model 和 Streaming API for XML。其中 SAX 和 StAX
采用了相似的模型 —— 将 XML 文件建模为元素流,DOM 采用了树形模型。带来的结果是 SAX 和 StAX 运行时空间相对 DOM
紧凑。状态保持能力则依次 SAX -> StAX -> DOM 变强。特别值得一提的是 StAX 技术是最新引进的 XML
处理技术,它结合了 SAX 和 DOM 的优点。清单 8 给出了一个粗略度量 SAX、StAX、DOM 三个框架解析同一个 XML 文件的运行效率的代码。
清单 8. 度量 XML 解析框架的运行时间
public class StAXTest {
public static void main(String[] args) {
final String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<work-contact-info>" +
"<Location>Shanghai-shuion-333</Location>" +
"<Postal>200020</Postal>" +
"<Tel><fix>63262299</fix>" +
"<mobile>1581344454</mobile></Tel>" +
"<Appellation>Mr. Wang</Appellation>" +
"</work-contact-info>";
for (int i = 0; i < 10000; i++) {
StAX(xml);
}
for (int i = 0; i < 10000; i++) {
SAX(xml);
}
for (int i = 0; i < 10000; i++) {
DOM(xml);
}
long current = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
StAX(xml);
}
current = System.currentTimeMillis() - current;
System.out.println(current);
current = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
SAX(xml);
}
current = System.currentTimeMillis() - current;
System.out.println(current);
current = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
DOM(xml);
}
current = System.currentTimeMillis() - current;
System.out.println(current);
}
private static void StAX(final String xml) {
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
InputStream input;
try {
input = new ByteArrayInputStream(xml.getBytes());
XMLEventReader xmlEventReader = inputFactory
.createXMLEventReader(input);
while (xmlEventReader.hasNext()) {
XMLEvent event = xmlEventReader.nextEvent();
if (event.isStartElement()) {
StartElement startElement = event.asStartElement();
}
if (event.isCharacters()) {
Characters text = event.asCharacters();
if (!text.isWhiteSpace()) {
}
}
}
} catch (XMLStreamException e) {
e.printStackTrace();
}
}
private static void SAX(final String xml) {
SAXParserFactory f = SAXParserFactory.newInstance();
InputStream input;
try {
SAXParser p = f.newSAXParser();
input = new ByteArrayInputStream(xml.getBytes());
p.parse(input, new DefaultHandler());
} catch (Exception e) {
e.printStackTrace();
}
}
private static void DOM(final String xml) {
DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
InputStream input;
try {
DocumentBuilder p = f.newDocumentBuilder();
input = new ByteArrayInputStream(xml.getBytes());
p.parse(input);
} catch (Exception e) {
e.printStackTrace();
}
}
}
得出的数据如下:
2734
4953
6516
可以看出解析速度按 SAX -> StAX -> DOM 依次变慢。这组数据从一个侧面反映了这三种技术的特性。SAX
处理小的,简单的 XML 文件更高效。基于三种 XML 解析技术,Java SE 6 SDK 又提供了数据格式转换框架 —— XSLT。同时
XSLT 技术和其他很多的 JDK 框架一样,是一个开放框架。它提供了一些抽象类和接口,让应用程序可以根据需求,开发出不同的 XML
数据处理和转换工具。然后通过之前叙述的 Service Provider 机制,将这些工具“插入”JDK 中。表 1 罗列了 SAX、StAX、DOM、XSLT 在 JDK 中的位置:
表 1. SAX,StAX,DOM,XSLT 在 JDK 中的位置
| SAX | StAX | DOM | XSLT |
| javax.xml.parsers |
javax.xml.stream |
javax.xml.parsers |
javax.xml.transform |
| |
javax.xml.stream.events |
|
javax.xml.transform.dom |
| |
javax.xml.stream.util |
|
javax.xml.transform.sax |
| |
|
|
javax.xml.transform.stax |
| |
|
|
javax.xml.transform.stream |
Web 服务
基
于 XML 的数据通常被作为 Web 服务之间互相调用的标准的数据传输文件格式。Java SE 6 SDK 中基于 XML
的解析技术,也提供了 Web 服务的 API 支持。和较早的 JDK 5 相比,新版本的 JDK Web 服务功能更改了名称 —— 从
JAX-RPC 变成 JAX-WS。JDK 5 只支持基于 remote-procedure-call 的 Web 服务,JDK 6
在此基础上,还支持基于 SOAP message 的 Web 服务实现。下面将给出一个例子,基于 SOAP message,实现一个简单的
Web 服务。
清单 9 给出了开发一个 Web services EndPoint 的代码。
清单 9. 一个 Web service‘Hello’服务
package hello;
import javax.jws.WebService;
import javax.jws.WebMethod;
import javax.xml.ws.Endpoint;
@WebService
public class Hello {
@WebMethod
public String hello(String name) {
return "Hello, " + name + "\n";
}
public static void main(String[] args) {
// create and publish an endpoint
Hello hello = new Hello();
Endpoint endpoint = Endpoint.publish("http://localhost:8080/hello", hello);
}
}
2,使用 apt 编译 Hello.java,产生辅助文件:
apt -d sample example/Calculator.java
运行完这条命令之后,example 目录下面多出了一个 jaxws 子目录如 图 6 所示。Apt 工具在该目录里生成了发布 Hello Web service 所必需的两个辅助文件。
图 6. example 目录
发布 Hello Web service:
java -cp sample hello.Hello
将浏览器指向 http://localhost:8080/hello?wsdl 会产生如 图 7 所示页面。
图 7. 发布的 Hello Web service
Java SE 6 SDK 内嵌了一个轻量级的 HTTP Server,方便开发者验证简单的 Web service 功能。通过以上三步,一个 Web service Endpoint 就部署完成,下面将开发一个调用 Hello 服务的客户端。
为 Web 服务的客户端产生存根文件:
wsimport -p sample -keep http://localhost:8080/hello?wsdl
这将会在 sample 目录下产生如 图 8 所示的文件。这一步实际是根据上面 URL 指向的 WSDL 文件,通过 JAXB 技术,生成了相应的 Java 对象。
图 8. wsimport 产生的文件
开发,编译,运行 Web 服务客户程序。清单 10 给出了使用 Hello 服务的客户程序。
清单 10. 使用 Hello 服务的客户程序
package sample;
class HelloApp {
public static void main(String args[]) {
HelloService service = new HelloService();
Hello helloProxy = service.getHelloPort();
String hello = helloProxy.hello("developer works");
System.out.println(hello);
}
}
图 9 是编译并运行该客户程序产生的结果:
图 9. 调用 Hello 服务
可
以说在 Java SE 6 SDK 中,Web 服务的开发过程被大大简化了。原来开发中需要手工重复劳动产生的文件,可以使用工具自动生成。比如
WSDL 文件可以自动生成,和 WSDL 绑定的 Java 对象也自动生成,部署(本文仅指 JDK 提供的轻量 HTTP server
部署环境)也大大简化。这些全部归功于 JDK 6 中引入的一些新的 JSR 实现,即一些 API 和工具。表 2 给出了 JDK6 中为 Web 服务 API 提供支持的包。
表 2. JDK 中提供 Web 服务 API 支持的包
| JSR | Package |
| JSR 224
Java API for XML-Based Web Services 2.0
|
javax.xml.ws |
| javax.xml.ws.handler |
| javax.xml.ws.handler.soap |
| javax.xml.ws.http |
| javax.xml.ws.soap |
| javax.xml.ws.spi |
| JSR 222
Java Architecture for XML Binding
(JAXB) 2.0
|
javax.xml.bind |
| javax.xml.bind.annotation |
| javax.xml.bind.annotation.adapters |
| javax.xml.bind.attachment |
| javax.xml.bind.helpers |
| javax.xml.bind.util |
| JSR 181
Web Services Metadata for the Java
Platform
|
javax.jws |
| javax.jws.soap |
除此之外 JDK 6 还提供了一些工具,包括 wsgen, wsimport 以及 Java 调用的轻量级 HTTP server。API 和工具联合提供了一个简单的 Web services IDE 开发环境,可以简化 Web 服务应用的开发。
Java class 和 XML 文件的绑定
从
上一段关于 Web 服务的叙述中,我们能够发现开发和部署 Web 服务的过程中存在多次 Java 对象和 XML
文件转化的过程。比如开发和部署服务的时候,将一个 Web Service EndPoint 发布成为一个 WSDL,或者使用服务的时候,将一个
WSDL 文件转换成一组 Java 对象。所有的转换,都是通过工具自动完成的。这里存在一些问题,Java 对象的类型转换成 XML
元素是需要符合一定的标准,还是随意转换呢?如果按照标准转换,那么这个标准是什么样子的?比如 Java 中的 int 类型是应该变成 <int></int> 呢,还是 <integer></integer>。如 表 2 列出,JSR222- Java Architecture for XML Binding (JAXB) 2.0 标准为这些问题给出了一个规范的解答。
首先示范一个简单的例子,将根据一个 XML 文件的 schema,转换成 Java 对象。还是以 清单 6 中的数据文件为依据。构造一个 XML schema 文件,如 清单 11 所示。要运行这个例子,首先需要下载一个 JAXB Reference Implementation jar(下载请参见 参考资源),并将该 jar 文件加入到 classpath 中。
清单 11. 用于绑定的 workcontactinfo.xsd 文件
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="workcontactinfo" type="workcontactinfo" />
<xsd:complexType name="workcontactinfo">
<xsd:sequence>
<xsd:element ref="Location" maxOccurs="1" minOccurs="1" />
<xsd:element ref="Postal" maxOccurs="1" minOccurs="1" />
<xsd:element ref="tel" maxOccurs="1" minOccurs="1" />
<xsd:element ref="Appellation" maxOccurs="1" minOccurs="1" />
</xsd:sequence>
</xsd:complexType>
<xsd:element name="tel" type="tel" />
<xsd:complexType name="tel">
<xsd:sequence>
<xsd:element ref="fix" maxOccurs="1" minOccurs="1" />
<xsd:element ref="mobile" maxOccurs="1" minOccurs="1" />
</xsd:sequence>
</xsd:complexType>
<xsd:element name="Location" type="xsd:string" />
<xsd:element name="Postal" type="xsd:string" />
<xsd:element name="Appellation" type="xsd:string" />
<xsd:element name="fix" type="xsd:string" />
<xsd:element name="mobile" type="xsd:string" />
</xsd:schema>
- 运行命令
xjc workcontactinfo.xsd。将会在当前目录下生成一个 generated 子目录。
- 运行命令
javac generated\*.java,编译所有生成的 Java 文件。
- 操作生成的 Java 对象。清单 12 给出了一个操作生成的 java 对象的例子。要注意,一定要先将 JAXB Reference Implementation jar 放到 classpath 中。
清单 12. 调用生成的 Java 对象
import generated.*;
import java.io.FileOutputStream;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
public class JAXBTest {
public static void main(String[] args) {
try {
JAXBContext jContext = JAXBContext.newInstance("generated");
ObjectFactory factory = new ObjectFactory();
Workcontactinfo contactinfo = (Workcontactinfo) (factory
.createWorkcontactinfo());
contactinfo.setAppellation("Mr. Wang");
contactinfo.setLocation("Shanghai-shuion-333");
contactinfo.setPostal("200020");
Tel tel = (Tel) (factory.createTel());
tel.setFix("123456");
tel.setMobile("1376666666");
contactinfo.setTel(tel);
Marshaller marshaller = jContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
Boolean.TRUE);
marshaller.marshal(contactinfo, new FileOutputStream(
"workcontactinfo1.xml"));
System.out.println("java tree converted into xml & filed");
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行这个程序,就能生成一个 XML 数据文件,如 清单 13。
清单 13. XML 数据文件
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<workcontactinfo>
<Location>Shanghai-shuion-333</Location>
<Postal>200020</Postal>
<tel>
<fix>123456</fix>
<mobile>1376666666</mobile>
</tel>
<A