- 浏览: 415160 次
- 性别:
- 来自: 广州
文章分类
最新评论
-
liyuanhoa_:
...
struts2.0中struts.xml配置文件详解 -
chenmingde:
...
Velocity应用(一) -
weizhikai_ai:
第二十六,当一个线程进入一个对象的一个synchronized ...
Java常见面试题(含答案) -
Aurora_lr:
...
Spring宠物商店学习笔记(一) - -
zs911zs:
all copy from http://www.iteye ...
Mule入门文档
回顾
本专栏的 第一篇中,您已经了解一些重要的术语: 编组和 解组(unmarshalling)是数据绑定世界固有的概念;不过还有一些新的术语,如 往返和 语义等价。往返是指从 XML 转换成 Java 代码然后再转换回去的过程。数据绑定往返能力的质量通过输入和输出文档匹配的程度衡量。语义等价使得比较成为可能,它允许丢弃 XML 中不重要的成分如可以忽略的空格,从而可以进行有效的比较。
在 第 2 篇中,我介绍了一个简单的 XML 文档,在这里再写出来,如清单 1 所示。
清单 1. 吉他的基本 XML 清单(guitars.xml)
<guitars>
<guitar id="10021">
<builder luthier="true">Ryan</builder>
<model>Mission Grand Concert</model>
<back-sides>Brazilian Rosewood</back-sides>
<top>Adirondack Spruce</top>
<notes>
<![CDATA[
Just unbelievable... this guitar has all the tone &
resonance you could ever want. I mean, <<WOW!!!>> This
is a lifetime guitar.
]]>
</notes>
</guitar>
<guitar id="0923">
<builder smallShop="true">Bourgeois</builder>
<model>OMC</model>
<back-sides>Bubinga</back-sides>
<top>Adirondack Spruce</top>
</guitar>
<guitar id="11091">
<builder>Martin & Company</builder>
<model>OM-28VR</model>
<back-sides>Indian Rosewood</back-sides>
<top bearclaw="true">Sitka Spruce</top>
<notes>It's certainly true that Martin isn't the only game in town anymore.
Still, the OM-28VR is one of their best models... and this one
has some fabulous bearclaw to boot. Nice specimen of a
still-important guitar manufacturer.
</notes>
</guitar>
</guitars>
我还为这个文档准备了一个模式,为了简化起见这里不再重复列出,要说明的是如何从这个模式生成 Java 源文件,如清单 2 所示。
清单 2. 生成的JAXB 类
C:\developerworks>xjc -p com.ibm.dw guitars.xsd -d src
parsing a schema...
compiling a schema...
com\ibm\dw\impl\runtime\MSVValidator.java
com\ibm\dw\impl\runtime\SAXUnmarshallerHandlerImpl.java
com\ibm\dw\impl\runtime\ErrorHandlerAdaptor.java
com\ibm\dw\impl\runtime\AbstractUnmarshallingEventHandlerImpl.java
com\ibm\dw\impl\runtime\UnmarshallableObject.java
com\ibm\dw\impl\runtime\SAXMarshaller.java
com\ibm\dw\impl\runtime\XMLSerializer.java
com\ibm\dw\impl\runtime\ContentHandlerAdaptor.java
com\ibm\dw\impl\runtime\UnmarshallingEventHandlerAdaptor.java
com\ibm\dw\impl\runtime\SAXUnmarshallerHandler.java
com\ibm\dw\impl\runtime\ValidatorImpl.java
com\ibm\dw\impl\runtime\ValidatableObject.java
com\ibm\dw\impl\runtime\UnmarshallerImpl.java
com\ibm\dw\impl\runtime\NamespaceContext2.java
com\ibm\dw\impl\runtime\Discarder.java
com\ibm\dw\impl\runtime\NamespaceContextImpl.java
com\ibm\dw\impl\runtime\ValidatingUnmarshaller.java
com\ibm\dw\impl\runtime\UnmarshallingContext.java
com\ibm\dw\impl\runtime\GrammarInfoImpl.java
com\ibm\dw\impl\runtime\ValidationContext.java
要保证生成并编译了这些 Java 源文件以备使用。详细的步骤请参阅本系列的 上一篇文章。
回页首
XML 到 Java 代码
只要生成并准备好这些类,就可以把 清单 1中的 XML 文档解组成 JAXB 在内存中的模型。这是测试 JAXB 往返能力的第一步。因为这不是一篇关于 JAXB 基础的文章(这类文章请参阅 参考资料),我仅仅把代码列在下面,如清单 3 所示。
清单 3. 解组 XML 到 Java 代码
import java.io.FileInputStream;
import javax.xml.bind.*;
// Import generated classes
import com.ibm.dw.*;
public class RoundTripper {
private String inputFilename;
private String outputFilename;
private JAXBContext jc;
private final String PACKAGE_NAME = "com.ibm.dw";
public RoundTripper(String inputFilename, String outputFilename) throws Exception {
this.inputFilename = inputFilename;
this.outputFilename = outputFilename;
jc = JAXBContext.newInstance(PACKAGE_NAME);
}
public Guitars unmarshal() throws Exception {
Unmarshaller u = jc.createUnmarshaller();
return (Guitars)u.unmarshal(new FileInputStream(inputFilename));
}
public static void main(String[] args) {
if (args.length < 2) {
System.err.println("Incorrect usage: java RoundTripper" +
"[input XML filename] [output XML filename]");
return;
}
try {
RoundTripper rt = new RoundTripper(args[0], args[1]);
Guitars guitars = rt.unmarshal();
} catch (Exception e) {
e.printStackTrace();
return;
}
}
}
注意:如果设置和运行这些类有问题,请参考本文的最后一节“ 运行示例程序”。
在这里一些人可能认为应该打印出内存中的版本。但是,用于打印内存中某些内容的 API 也可用于把数据写入输出流,因此这一步实际上不需要。
回页首
Java 代码到 XML
现在可以要求 JAXB 把内存中的表示再返回到 XML。这样就可以观察输入文件和输出文件的区别。我已经向 RoundTripper 类中增加了一些代码来完成这项工作,如清单 4 所示。
清单 4. 编组 Java 到 XML
import java.io.FileInputStream;
import java.io.FileOutputStream;
import javax.xml.bind.*;
// Import generated classes
import com.ibm.dw.*;
public class RoundTripper {
private String inputFilename;
private String outputFilename;
private JAXBContext jc;
private final String PACKAGE_NAME = "com.ibm.dw";
public RoundTripper(String inputFilename, String outputFilename) throws Exception {
this.inputFilename = inputFilename;
this.outputFilename = outputFilename;
jc = JAXBContext.newInstance(PACKAGE_NAME);
}
public Guitars unmarshal() throws Exception {
Unmarshaller u = jc.createUnmarshaller();
return (Guitars)u.unmarshal(new FileInputStream(inputFilename));
}
public void marshal(Guitars guitars) throws Exception {
Marshaller m = jc.createMarshaller();
m.marshal(guitars, new FileOutputStream(outputFilename));
}
public static void main(String[] args) {
if (args.length < 2) {
System.err.println("Incorrect usage: java RoundTripper" +
"[input XML filename] [output XML filename]");
return;
}
try {
RoundTripper rt = new RoundTripper(args[0], args[1]);
Guitars guitars = rt.unmarshal();
rt.marshal(guitars);
} catch (Exception e) {
e.printStackTrace();
return;
}
}
}
同样,这里的代码也相当简单,意义明确。我使用 guitars.xml 作为输入文件运行这个程序,并提供 output.xml 作为输出文件名。没有什么输出值得一提,和写到终端上的文本一样,不过执行这个过程您将得到一个新的文件(output.xml)。理论上讲,这个文件应该是 guitars.xml 的完全复制,因为在内存中没有改变该文件。
回页首
拿苹果和苹果比较
生成 output.xml 之后打开它。即使不完全相同,也应该和清单 5 类似。
清单 5. output.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<guitars>
<guitar id="10021">
<builder luthier="true">Ryan<builder>
<model>Mission Grand Concert</model>
<back-sides>Brazilian Rosewood<back-sides>
<top>Adirondack Spruce<top>
<notes>
Just unbelievable... this guitar has all the tone &
resonance you could ever want. I mean, <<WOW!!!>> This
is a lifetime guitar.
<notes>
</guitar>
<guitar id="0923">
<builder smallShop="true">Bourgeois</builder>
<model>OMC<model>
<back-sides>Bubinga<back-sides>
<top>Adirondack Spruce</top>
<guitar>
<guitar id="11091">
<builder>Martin & Company<builder>
<model>OM-28VR<model>
<back-sides>Indian Rosewood<back-sides>
<top bearclaw="true">Sitka Spruce<top>
<notes>It's certainly true that Martin isn't the only game in town anymore.
Still, the OM-28VR is one of their best models... and this one
has some fabulous bearclaw to boot. Nice specimen of a
still-important guitar manufacturer.
<notes>
<guitar>
<guitars>
现在有了输入和输出文件,通过互相比较可以看看 JAXB 在往返中是如何工作的(原始文件如 清单 1所示)。
增加 XML 声明
首先,注意到输入文件没有 XML 声明(以 <xml version=... 开始的那一行)。JAXB 自动在输出中插入这一行。这看起来似乎是一个小问题,但非常重要——现在常常需要在一个 XML 文档中包含另一个 XML 文件,特别是在使用 SOAP 或者其他传输技术的时候。插入 XML 声明的问题在与一个 XML 文档只能有一个声明。如果把 guitars.xml 插入另一个 XML 文档,您并没有违反这一规则;但是另一方面如果插入的是 output.xml,问题就出来了。因此现在 JAXB 又一个需要注意的特性。
去掉 CDATA 节
还要注意,原始 XML 文档中的 CDATA 节被去掉了。从技术上讲这并没有违反语义等价的规则,两个文档的内容在语义上是相同的。第一个文档使用 CDATA 避免实体引用,而在输出文档中为了支持实体引用而放弃了 CDATA。这更多的是文档的事实等价问题而非 语义等价问题。虽然这不是一个重要的问题,但也应该注意。
空白处理
高兴地看到正确地处理了空白。虽然去掉了 CDATA 节,但空白正确地保留了下来。此外,关于 Martin OM-28VR 吉他描述中的长空白也原样保留了下来,这方面解决得很好。
回页首
为了确认重新测试一遍
评价往返能力最好的也是最有效的方式是 重新测试往返过程。但是要注意,我并不是说简单地再进行一次测试。相反,这次把输出文件(output.xml)提供给往返程序作为 输入文件。如果说这个过程向 XML 文件中引入了不应该有的什么内容,那就是每次后续的往返创建的输出都和原始文件(guitars.xml)离得更远一点。这对于隔离问题是一种很好的方式。好的数据绑定工具应该能够一遍一遍地总是创建相同的文件,特别是在最初的往返过程之后。
在这一步中,我要求 RoundTripper 生成 retest.xml,以 output.xml 作为源 XML。结果如清单 6 所示。
清单 6. retest.xml
<xml version="1.0" encoding="UTF-8" standalone="yes"?>
<guitars>
<guitar id="10021">
<builder luthier="true">Ryan<builder>
<model>Mission Grand Concert</model>
<back-sides>Brazilian Rosewood<back-sides>
<top>Adirondack Spruce<top>
<notes>
Just unbelievable... this guitar has all the tone &
resonance you could ever want. I mean, <<WOW!!!>> This
is a lifetime guitar.
<notes>
<guitar>
<guitar id="0923">
<builder smallShop="true">Bourgeois<builder>
<model>OMC<model>
<back-sides>Bubinga<back-sides>
<top>Adirondack Spruce<top>
<guitar>
<guitar id="11091">
<builder>Martin & Company</builder>
<model>OM-28VR<model>
<back-sides>Indian Rosewood<back-sides>
<top bearclaw="true">Sitka Spruce<top>
<notes>It's certainly true that Martin isn't the only game in town anymore.
Still, the OM-28VR is one of their best models... and this one
has some fabulous bearclaw to boot. Nice specimen of a
still-important guitar manufacturer.
<notes>
</guitar>
<guitars>
好消息是 清单 5和 清单 6完全相同,这说明 JAXB 经过最初的往返步骤之后可以很好地工作。
总的来说 JAXB 表现得很好。虽然我认为自动增加 XML 声明确实是一个问题,但和影响内容的 API 相比不算很糟。JAXB 还以和预期稍有不同的方式处理 CDATA 节,但确实保持了语义等价。下一篇文章中,我将介绍进一步影响输出文件的各种选项,手工解决 JAXB 造成的一些问题。但总而言之,JAXB 证明自己能够很好地按照期望保持输入文档。
回页首
运行示例程序
最后让我们来分享我的一个秘技,用于轻松制作 classpath 和 JAXB 示例的 Ant 设置。清单 7 是我在本文中使用的 Ant 构建文件。您要使用这个文件,只需要把路径改为您自己的 XML 输入文件,以及您的 JAXB JAR 文件。
清单 7. Ant 构建文件
<?xml version="1.0"?>
<project basedir="." default="roundtrip">
<property name="jwsdp.home" value="c:\jwsdp-1.3"/>
<property name="xml.inputFile" value="guitars.xml"/>
<property name="xml.outputFile" value="output.xml"/>
<property name="xml.retestFile" value="retest.xml"/>
<path id="classpath">
<pathelement path="build"/>
<fileset dir="${jwsdp.home}" includes="jaxb/lib/*.jar"/>
<fileset dir="${jwsdp.home}" includes="jwsdp-shared/lib/*.jar"/>
<fileset dir="${jwsdp.home}" includes="jaxp/lib/**/*.jar"/>
<path>
<taskdef name="xjc" classname="com.sun.tools.xjc.XJCTask">
<classpath refid="classpath"/>
<taskdef>
<!-- compile Java source files -->
<target name="compile">
<!-- generate the Java content classes from the schema -->
<echo message="Compiling the schema external binding file..."/>
<xjc schema="guitars.xsd" package="com.ibm.dw" target="src"/>
<!-- compile all of the java sources -->
<echo message="Compiling the java source files..."/>
<javac srcdir="src" destdir="build" debug="on">
<classpath refid="classpath"/>
</javac>
<!-- Copy over the properties files -->
<copy todir="build">
<fileset dir="src">
<exclude name="**/*.java"/>
</fileset>
<copy>
<target>
<target name="roundtrip" depends="compile">
<echo message="Converting XML file to Java and back..."/>
<java classname="RoundTripper">
<arg value="${xml.inputFile}" />
<arg value="${xml.outputFile}" />
<classpath refid="classpath" />
</java>
<target>
<target name="roundtrip-retest" depends="roundtrip">
<echo message="Converting XML file to Java and back... (Second iteration)"/>
<java classname="RoundTripper">
<arg value="${xml.outputFile}" />
<arg value="${xml.retestFile}" />
<classpath refid="classpath" />
<java>
<target>
<project>
默认情况下,这个文件将从模式生成源文件、编译这些源文件并复制需要的 JAXB 属性文件,然后编译并运行 RoundTripper 类。您可以手工运行 roundtrip-retest 目标,它执行第二遍往返过程,使用 output.xml 作为输入文件。该文件会使生活轻松许多,但愿您喜欢它!
参考资料
您可以参阅本文在 developerWorks 全球站点上的 英文原文.
阅读实用数据绑定专栏的 第一篇文章,Brett 分析了数据绑定中的几个重要概念,包括往返和语义等价。在 第二篇中,他考察了 JAXB 如何处理类的生成,以及对 API 接受的 XML 输入和输出有何影响( developerWorks,2004 年 5 月)。
关于如何使用这两种技术的更多信息,请访问 Brett McLaughlin 主持的 developerWorks“ XML 和 Java 技术”论坛。
阅读 Dennis Sosnoski 的文章“ 代码生成方法 — JAXB 及其它”( developerWorks,2003 年 1 月),他考察了使用 XML 文档的 W3C XML Schema 或者 DTD 语法的代码生成进行 XML 数据绑定的几种方法。
通过 Daniel Steinberg 撰写的 教程( developerWorks,2003 年 5 月)提高您的 JAXB 技巧。
试一试 Quick,另一种数据绑定框架。
通过 Brett McLaughlin 撰写的“ 使用 Quick 在 Java 对象和 XML 之间进行转换”( developerWorks,2002 年 8 月)进一步了解 Quick。
探索 Castor,代替 JAXB 的另一种数据绑定。
通过 Dennis Sosnoski 撰写的 这篇文章( developerWorks,2002 年 4 月)进一步了解 Castor。
尝试 JaxMe,JAXB API的一种开放源代码实现。
看一看 XMLBeans,另外一种开放源代码的数据绑定工具。
从 Jakarta 通用包获得文本解析工具。
通过 Sun 的 Web 站点了解 Sun XML API。
看一看 Brett 关于数据绑定的著作, Java and XML Data Binding (O'Reilly & Associates)。
在 developerWorks Developer Bookstore可以找到 各种关于 XML 的书籍。
在 developerWorks XML和 Java 技术专区可以找到更多关于数据绑定的资源。
了解如何才能成为一名 IBM 认证的 XML 及相关技术的开发人员。
关于作者
Brett McLaughlin 从 Logo 时代(还记得那个小三角吗?)就开始从事计算机。他目前专门使用 Java 相关技术构建应用程序基础设施。他最近几年为 Nextel Communications 和 Allegiance Telecom, Inc. 实现了这些基础设施。Brett 是 Java Apache 项目 Turbine 的缔造者之一,该项目使用 Java servlet 为 Web 应用程序开发建立了可重用的组件体系结构。他还参与了 EJBoss 项目(一种开放源代码的 EJB 应用程序服务器)和 Cocoon(一种开放源代码的 XML Web 发布引擎)。
本专栏的 第一篇中,您已经了解一些重要的术语: 编组和 解组(unmarshalling)是数据绑定世界固有的概念;不过还有一些新的术语,如 往返和 语义等价。往返是指从 XML 转换成 Java 代码然后再转换回去的过程。数据绑定往返能力的质量通过输入和输出文档匹配的程度衡量。语义等价使得比较成为可能,它允许丢弃 XML 中不重要的成分如可以忽略的空格,从而可以进行有效的比较。
在 第 2 篇中,我介绍了一个简单的 XML 文档,在这里再写出来,如清单 1 所示。
清单 1. 吉他的基本 XML 清单(guitars.xml)
<guitars>
<guitar id="10021">
<builder luthier="true">Ryan</builder>
<model>Mission Grand Concert</model>
<back-sides>Brazilian Rosewood</back-sides>
<top>Adirondack Spruce</top>
<notes>
<![CDATA[
Just unbelievable... this guitar has all the tone &
resonance you could ever want. I mean, <<WOW!!!>> This
is a lifetime guitar.
]]>
</notes>
</guitar>
<guitar id="0923">
<builder smallShop="true">Bourgeois</builder>
<model>OMC</model>
<back-sides>Bubinga</back-sides>
<top>Adirondack Spruce</top>
</guitar>
<guitar id="11091">
<builder>Martin & Company</builder>
<model>OM-28VR</model>
<back-sides>Indian Rosewood</back-sides>
<top bearclaw="true">Sitka Spruce</top>
<notes>It's certainly true that Martin isn't the only game in town anymore.
Still, the OM-28VR is one of their best models... and this one
has some fabulous bearclaw to boot. Nice specimen of a
still-important guitar manufacturer.
</notes>
</guitar>
</guitars>
我还为这个文档准备了一个模式,为了简化起见这里不再重复列出,要说明的是如何从这个模式生成 Java 源文件,如清单 2 所示。
清单 2. 生成的JAXB 类
C:\developerworks>xjc -p com.ibm.dw guitars.xsd -d src
parsing a schema...
compiling a schema...
com\ibm\dw\impl\runtime\MSVValidator.java
com\ibm\dw\impl\runtime\SAXUnmarshallerHandlerImpl.java
com\ibm\dw\impl\runtime\ErrorHandlerAdaptor.java
com\ibm\dw\impl\runtime\AbstractUnmarshallingEventHandlerImpl.java
com\ibm\dw\impl\runtime\UnmarshallableObject.java
com\ibm\dw\impl\runtime\SAXMarshaller.java
com\ibm\dw\impl\runtime\XMLSerializer.java
com\ibm\dw\impl\runtime\ContentHandlerAdaptor.java
com\ibm\dw\impl\runtime\UnmarshallingEventHandlerAdaptor.java
com\ibm\dw\impl\runtime\SAXUnmarshallerHandler.java
com\ibm\dw\impl\runtime\ValidatorImpl.java
com\ibm\dw\impl\runtime\ValidatableObject.java
com\ibm\dw\impl\runtime\UnmarshallerImpl.java
com\ibm\dw\impl\runtime\NamespaceContext2.java
com\ibm\dw\impl\runtime\Discarder.java
com\ibm\dw\impl\runtime\NamespaceContextImpl.java
com\ibm\dw\impl\runtime\ValidatingUnmarshaller.java
com\ibm\dw\impl\runtime\UnmarshallingContext.java
com\ibm\dw\impl\runtime\GrammarInfoImpl.java
com\ibm\dw\impl\runtime\ValidationContext.java
要保证生成并编译了这些 Java 源文件以备使用。详细的步骤请参阅本系列的 上一篇文章。
回页首
XML 到 Java 代码
只要生成并准备好这些类,就可以把 清单 1中的 XML 文档解组成 JAXB 在内存中的模型。这是测试 JAXB 往返能力的第一步。因为这不是一篇关于 JAXB 基础的文章(这类文章请参阅 参考资料),我仅仅把代码列在下面,如清单 3 所示。
清单 3. 解组 XML 到 Java 代码
import java.io.FileInputStream;
import javax.xml.bind.*;
// Import generated classes
import com.ibm.dw.*;
public class RoundTripper {
private String inputFilename;
private String outputFilename;
private JAXBContext jc;
private final String PACKAGE_NAME = "com.ibm.dw";
public RoundTripper(String inputFilename, String outputFilename) throws Exception {
this.inputFilename = inputFilename;
this.outputFilename = outputFilename;
jc = JAXBContext.newInstance(PACKAGE_NAME);
}
public Guitars unmarshal() throws Exception {
Unmarshaller u = jc.createUnmarshaller();
return (Guitars)u.unmarshal(new FileInputStream(inputFilename));
}
public static void main(String[] args) {
if (args.length < 2) {
System.err.println("Incorrect usage: java RoundTripper" +
"[input XML filename] [output XML filename]");
return;
}
try {
RoundTripper rt = new RoundTripper(args[0], args[1]);
Guitars guitars = rt.unmarshal();
} catch (Exception e) {
e.printStackTrace();
return;
}
}
}
注意:如果设置和运行这些类有问题,请参考本文的最后一节“ 运行示例程序”。
在这里一些人可能认为应该打印出内存中的版本。但是,用于打印内存中某些内容的 API 也可用于把数据写入输出流,因此这一步实际上不需要。
回页首
Java 代码到 XML
现在可以要求 JAXB 把内存中的表示再返回到 XML。这样就可以观察输入文件和输出文件的区别。我已经向 RoundTripper 类中增加了一些代码来完成这项工作,如清单 4 所示。
清单 4. 编组 Java 到 XML
import java.io.FileInputStream;
import java.io.FileOutputStream;
import javax.xml.bind.*;
// Import generated classes
import com.ibm.dw.*;
public class RoundTripper {
private String inputFilename;
private String outputFilename;
private JAXBContext jc;
private final String PACKAGE_NAME = "com.ibm.dw";
public RoundTripper(String inputFilename, String outputFilename) throws Exception {
this.inputFilename = inputFilename;
this.outputFilename = outputFilename;
jc = JAXBContext.newInstance(PACKAGE_NAME);
}
public Guitars unmarshal() throws Exception {
Unmarshaller u = jc.createUnmarshaller();
return (Guitars)u.unmarshal(new FileInputStream(inputFilename));
}
public void marshal(Guitars guitars) throws Exception {
Marshaller m = jc.createMarshaller();
m.marshal(guitars, new FileOutputStream(outputFilename));
}
public static void main(String[] args) {
if (args.length < 2) {
System.err.println("Incorrect usage: java RoundTripper" +
"[input XML filename] [output XML filename]");
return;
}
try {
RoundTripper rt = new RoundTripper(args[0], args[1]);
Guitars guitars = rt.unmarshal();
rt.marshal(guitars);
} catch (Exception e) {
e.printStackTrace();
return;
}
}
}
同样,这里的代码也相当简单,意义明确。我使用 guitars.xml 作为输入文件运行这个程序,并提供 output.xml 作为输出文件名。没有什么输出值得一提,和写到终端上的文本一样,不过执行这个过程您将得到一个新的文件(output.xml)。理论上讲,这个文件应该是 guitars.xml 的完全复制,因为在内存中没有改变该文件。
回页首
拿苹果和苹果比较
生成 output.xml 之后打开它。即使不完全相同,也应该和清单 5 类似。
清单 5. output.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<guitars>
<guitar id="10021">
<builder luthier="true">Ryan<builder>
<model>Mission Grand Concert</model>
<back-sides>Brazilian Rosewood<back-sides>
<top>Adirondack Spruce<top>
<notes>
Just unbelievable... this guitar has all the tone &
resonance you could ever want. I mean, <<WOW!!!>> This
is a lifetime guitar.
<notes>
</guitar>
<guitar id="0923">
<builder smallShop="true">Bourgeois</builder>
<model>OMC<model>
<back-sides>Bubinga<back-sides>
<top>Adirondack Spruce</top>
<guitar>
<guitar id="11091">
<builder>Martin & Company<builder>
<model>OM-28VR<model>
<back-sides>Indian Rosewood<back-sides>
<top bearclaw="true">Sitka Spruce<top>
<notes>It's certainly true that Martin isn't the only game in town anymore.
Still, the OM-28VR is one of their best models... and this one
has some fabulous bearclaw to boot. Nice specimen of a
still-important guitar manufacturer.
<notes>
<guitar>
<guitars>
现在有了输入和输出文件,通过互相比较可以看看 JAXB 在往返中是如何工作的(原始文件如 清单 1所示)。
增加 XML 声明
首先,注意到输入文件没有 XML 声明(以 <xml version=... 开始的那一行)。JAXB 自动在输出中插入这一行。这看起来似乎是一个小问题,但非常重要——现在常常需要在一个 XML 文档中包含另一个 XML 文件,特别是在使用 SOAP 或者其他传输技术的时候。插入 XML 声明的问题在与一个 XML 文档只能有一个声明。如果把 guitars.xml 插入另一个 XML 文档,您并没有违反这一规则;但是另一方面如果插入的是 output.xml,问题就出来了。因此现在 JAXB 又一个需要注意的特性。
去掉 CDATA 节
还要注意,原始 XML 文档中的 CDATA 节被去掉了。从技术上讲这并没有违反语义等价的规则,两个文档的内容在语义上是相同的。第一个文档使用 CDATA 避免实体引用,而在输出文档中为了支持实体引用而放弃了 CDATA。这更多的是文档的事实等价问题而非 语义等价问题。虽然这不是一个重要的问题,但也应该注意。
空白处理
高兴地看到正确地处理了空白。虽然去掉了 CDATA 节,但空白正确地保留了下来。此外,关于 Martin OM-28VR 吉他描述中的长空白也原样保留了下来,这方面解决得很好。
回页首
为了确认重新测试一遍
评价往返能力最好的也是最有效的方式是 重新测试往返过程。但是要注意,我并不是说简单地再进行一次测试。相反,这次把输出文件(output.xml)提供给往返程序作为 输入文件。如果说这个过程向 XML 文件中引入了不应该有的什么内容,那就是每次后续的往返创建的输出都和原始文件(guitars.xml)离得更远一点。这对于隔离问题是一种很好的方式。好的数据绑定工具应该能够一遍一遍地总是创建相同的文件,特别是在最初的往返过程之后。
在这一步中,我要求 RoundTripper 生成 retest.xml,以 output.xml 作为源 XML。结果如清单 6 所示。
清单 6. retest.xml
<xml version="1.0" encoding="UTF-8" standalone="yes"?>
<guitars>
<guitar id="10021">
<builder luthier="true">Ryan<builder>
<model>Mission Grand Concert</model>
<back-sides>Brazilian Rosewood<back-sides>
<top>Adirondack Spruce<top>
<notes>
Just unbelievable... this guitar has all the tone &
resonance you could ever want. I mean, <<WOW!!!>> This
is a lifetime guitar.
<notes>
<guitar>
<guitar id="0923">
<builder smallShop="true">Bourgeois<builder>
<model>OMC<model>
<back-sides>Bubinga<back-sides>
<top>Adirondack Spruce<top>
<guitar>
<guitar id="11091">
<builder>Martin & Company</builder>
<model>OM-28VR<model>
<back-sides>Indian Rosewood<back-sides>
<top bearclaw="true">Sitka Spruce<top>
<notes>It's certainly true that Martin isn't the only game in town anymore.
Still, the OM-28VR is one of their best models... and this one
has some fabulous bearclaw to boot. Nice specimen of a
still-important guitar manufacturer.
<notes>
</guitar>
<guitars>
好消息是 清单 5和 清单 6完全相同,这说明 JAXB 经过最初的往返步骤之后可以很好地工作。
总的来说 JAXB 表现得很好。虽然我认为自动增加 XML 声明确实是一个问题,但和影响内容的 API 相比不算很糟。JAXB 还以和预期稍有不同的方式处理 CDATA 节,但确实保持了语义等价。下一篇文章中,我将介绍进一步影响输出文件的各种选项,手工解决 JAXB 造成的一些问题。但总而言之,JAXB 证明自己能够很好地按照期望保持输入文档。
回页首
运行示例程序
最后让我们来分享我的一个秘技,用于轻松制作 classpath 和 JAXB 示例的 Ant 设置。清单 7 是我在本文中使用的 Ant 构建文件。您要使用这个文件,只需要把路径改为您自己的 XML 输入文件,以及您的 JAXB JAR 文件。
清单 7. Ant 构建文件
<?xml version="1.0"?>
<project basedir="." default="roundtrip">
<property name="jwsdp.home" value="c:\jwsdp-1.3"/>
<property name="xml.inputFile" value="guitars.xml"/>
<property name="xml.outputFile" value="output.xml"/>
<property name="xml.retestFile" value="retest.xml"/>
<path id="classpath">
<pathelement path="build"/>
<fileset dir="${jwsdp.home}" includes="jaxb/lib/*.jar"/>
<fileset dir="${jwsdp.home}" includes="jwsdp-shared/lib/*.jar"/>
<fileset dir="${jwsdp.home}" includes="jaxp/lib/**/*.jar"/>
<path>
<taskdef name="xjc" classname="com.sun.tools.xjc.XJCTask">
<classpath refid="classpath"/>
<taskdef>
<!-- compile Java source files -->
<target name="compile">
<!-- generate the Java content classes from the schema -->
<echo message="Compiling the schema external binding file..."/>
<xjc schema="guitars.xsd" package="com.ibm.dw" target="src"/>
<!-- compile all of the java sources -->
<echo message="Compiling the java source files..."/>
<javac srcdir="src" destdir="build" debug="on">
<classpath refid="classpath"/>
</javac>
<!-- Copy over the properties files -->
<copy todir="build">
<fileset dir="src">
<exclude name="**/*.java"/>
</fileset>
<copy>
<target>
<target name="roundtrip" depends="compile">
<echo message="Converting XML file to Java and back..."/>
<java classname="RoundTripper">
<arg value="${xml.inputFile}" />
<arg value="${xml.outputFile}" />
<classpath refid="classpath" />
</java>
<target>
<target name="roundtrip-retest" depends="roundtrip">
<echo message="Converting XML file to Java and back... (Second iteration)"/>
<java classname="RoundTripper">
<arg value="${xml.outputFile}" />
<arg value="${xml.retestFile}" />
<classpath refid="classpath" />
<java>
<target>
<project>
默认情况下,这个文件将从模式生成源文件、编译这些源文件并复制需要的 JAXB 属性文件,然后编译并运行 RoundTripper 类。您可以手工运行 roundtrip-retest 目标,它执行第二遍往返过程,使用 output.xml 作为输入文件。该文件会使生活轻松许多,但愿您喜欢它!
参考资料
您可以参阅本文在 developerWorks 全球站点上的 英文原文.
阅读实用数据绑定专栏的 第一篇文章,Brett 分析了数据绑定中的几个重要概念,包括往返和语义等价。在 第二篇中,他考察了 JAXB 如何处理类的生成,以及对 API 接受的 XML 输入和输出有何影响( developerWorks,2004 年 5 月)。
关于如何使用这两种技术的更多信息,请访问 Brett McLaughlin 主持的 developerWorks“ XML 和 Java 技术”论坛。
阅读 Dennis Sosnoski 的文章“ 代码生成方法 — JAXB 及其它”( developerWorks,2003 年 1 月),他考察了使用 XML 文档的 W3C XML Schema 或者 DTD 语法的代码生成进行 XML 数据绑定的几种方法。
通过 Daniel Steinberg 撰写的 教程( developerWorks,2003 年 5 月)提高您的 JAXB 技巧。
试一试 Quick,另一种数据绑定框架。
通过 Brett McLaughlin 撰写的“ 使用 Quick 在 Java 对象和 XML 之间进行转换”( developerWorks,2002 年 8 月)进一步了解 Quick。
探索 Castor,代替 JAXB 的另一种数据绑定。
通过 Dennis Sosnoski 撰写的 这篇文章( developerWorks,2002 年 4 月)进一步了解 Castor。
尝试 JaxMe,JAXB API的一种开放源代码实现。
看一看 XMLBeans,另外一种开放源代码的数据绑定工具。
从 Jakarta 通用包获得文本解析工具。
通过 Sun 的 Web 站点了解 Sun XML API。
看一看 Brett 关于数据绑定的著作, Java and XML Data Binding (O'Reilly & Associates)。
在 developerWorks Developer Bookstore可以找到 各种关于 XML 的书籍。
在 developerWorks XML和 Java 技术专区可以找到更多关于数据绑定的资源。
了解如何才能成为一名 IBM 认证的 XML 及相关技术的开发人员。
关于作者
Brett McLaughlin 从 Logo 时代(还记得那个小三角吗?)就开始从事计算机。他目前专门使用 Java 相关技术构建应用程序基础设施。他最近几年为 Nextel Communications 和 Allegiance Telecom, Inc. 实现了这些基础设施。Brett 是 Java Apache 项目 Turbine 的缔造者之一,该项目使用 Java servlet 为 Web 应用程序开发建立了可重用的组件体系结构。他还参与了 EJBoss 项目(一种开放源代码的 EJB 应用程序服务器)和 Cocoon(一种开放源代码的 XML Web 发布引擎)。
发表评论
-
考察 JAXB,第 1 部分
2008-12-22 11:28 1528简述 不过在展开 JAXB 的讨论之前,我要简要地回顾一下 ... -
jaxb接口学习实践
2008-12-22 11:26 1714jdk带了支持jaxb的包,为javax.xml.bind.* ... -
jaxb 简介
2008-12-22 10:23 1149JavaTM Architecture for XML B ... -
XML解析技术
2008-11-26 10:37 1237Java中四种XML解析技术 ... -
关于struts框架中的xml解析
2008-11-21 14:02 1121degister In Action (xml解析) 引言 ...
相关推荐
JAXB2,全称为Java Architecture for XML Binding 2,是Java平台上的一个标准技术,用于在XML和Java对象之间进行绑定。它允许开发者通过简单的API将XML文档转换为Java对象,反之亦然,大大简化了XML数据处理。JAXB2...
JAXB2是JAXB的第二个主要版本,它引入了更强大的功能和改进,如注解支持,使得XML绑定更加直观和便捷。本教程将通过一个实际的demo实例来详细讲解如何使用JAXB2来生产Java类。 **1. JAXB2概述** JAXB2是Java SE 6及...
对于Eclipse,可以搜索并安装"JAXB2 Basics Tools"插件,它提供了诸如生成Java类、XML schema等实用工具。对于IntelliJ IDEA,虽然内置了一些基本的JAXB支持,但也可以安装如"Java2WSDL"这样的插件来增强功能。 **...
jaxb-2_1_9.zip jaxb最新版本 转:http://blog.sina.com.cn/s/blog_5ce5700e0100bowu.html 使用MyEclipse5.5+jboss-5.0.0.CR1+JDK1.6,在启动时报了一个错误: java.lang.LinkageError: JAXB 2.0 API is being ...
2. **XSD到Java**: JAXB提供了工具(如`xjc`)将XML Schema(XSD)文件转换为Java类。这使得基于XSD定义的XML结构可以轻松地在Java应用中使用。 3. **Marshalling和Unmarshalling**: Marshalling是将Java对象转换为...
2. **Java类到XML的转换**:将已有的Java对象转换成XML文档,只需调用JAXB提供的API,即可轻松完成序列化过程。 3. **XML到Java对象的绑定**:通过JAXB,可以解析XML文档并创建相应的Java对象实例,这在处理XML输入...
在这个"jaxb2 demo"中,我们将探讨JDK 1.6中的一些重要特性以及JAXB 2.0的相关应用。 1. **泛型增强**: Java JDK 1.6对泛型的支持进行了增强,包括类型推断(Type Inference)和泛型通配符的改进。类型推断使得在...
JAXB(Java Architecture for XML Binding)是Java SE的一部分,它允许开发者将XML文档和Java对象之间进行映射,实现XML数据的编解码。在Java 8中,JAXB是标准库的一部分,但自Java 9起,它被移出核心库,成为可选...
`jaxb-api`和`jaxb-impl`是JAXB框架的核心组成部分。这两个JAR文件在处理XML到Java对象的绑定过程中扮演着关键角色。 1. **jaxb-api.jar**: 这个库包含了JAXB API,即Java接口和抽象类,定义了JAXB的工作方式。它...
这些文档可以帮助开发者深入理解JAXB 2.0的工作原理,学习如何有效地使用它的各种功能,以及如何解决可能出现的问题。通过查阅这些文档,你可以更好地利用JAXB 2.0来实现XML数据与Java对象之间的无缝转换。
JAXB是Java SE和Java EE平台的标准部分,它提供了一种将XML文档与Java对象之间进行自动转换的方法,从而简化了XML数据处理。 **JAXB API** `jaxb-api-2.1.jar` 包含了JAXB规范定义的接口和抽象类,它是JAXB实现的...
**JAXB(Java Architecture for XML Binding)** 是Java平台中用于处理XML的...通过深入学习和实践,你可以充分利用JAXB的强大功能,提升XML操作的效率和便捷性。在Java项目中,掌握JAXB技术将对处理XML数据大有裨益。
在给定的例子中,我们将深入理解如何使用JAXB注解来生成XML。 1. **@XmlType**: 这个注解用于定义类的属性在XML输出中的顺序。在`WriterXml`类中,propOrder 属性指定了"id", "name", "age", "book"这四个属性的...
2. **效率**:由于JAXB是Java平台的标准部分,其性能通常优于许多第三方XML处理库。 3. **易用性**:JAXB提供了一套简洁的API,使得XML操作变得简单直观。 **在实际开发中的应用:** 1. **Web服务**:JAXB常用于...
在Java开发中,JAXB(Java Architecture for XML Binding)是一个用于将XML文档和Java对象之间进行绑定的技术。在处理XML文件时,特别是涉及到序列化和反序列化时,可能会遇到字符编码问题,即所谓的“乱码”。这个...
2. **jaxb1-impl.jar**:这是早期版本的JAXB实现,用于将Java对象和XML文档进行相互转换。它包含了运行时需要的类和接口,以便开发者可以将Java类映射到XML Schema,然后进行序列化和反序列化操作。 3. **jaxb-api....
在你的场景中,由于在Maven仓库找不到这些特定版本的JAXB,可能需要从其他来源获取,例如官方站点、第三方库托管服务,或者通过直接从源代码构建。另一种替代方案是,如果你的项目兼容JAXB 2.2.x或更早的版本,可以...
2. `javax.xml.stream-1.0.1.jar`:XML流处理API(StAX,Streaming API for XML)是另一个重要的库,它是JAXB可能依赖的基础组件。StAX提供了一种低级别的、事件驱动的XML解析方式,允许开发者按需读取或写入XML文档...