`
chenming47
  • 浏览: 95071 次
  • 性别: Icon_minigender_1
  • 来自: 厦门
社区版块
存档分类
最新评论

实用数据绑定: 深入考察 JAXB,第 2 部分

    博客分类:
  • jaxb
阅读更多
进一步考察 JAXB 的往返能力

Brett McLaughlin (brett@oreilly.com), 编辑, O'Reilly and Associates
Brett McLaughlin 从 Logo 时代(还记得那个小三角吗?)就开始从事计算机。他目前专门使用 Java 相关技术构建应用程序基础设施。他最近几年为 Nextel Communications 和 Allegiance Telecom, Inc. 实现了这些基础设施。Brett 是 Java Apache 项目 Turbine 的缔造者之一,该项目使用 Java servlet 为 Web 应用程序开发建立了可重用的组件体系结构。他还参与了 EJBoss 项目(一种开放源代码的 EJB 应用程序服务器)和 Cocoon(一种开放源代码的 XML Web 发布引擎)。

简介: 本专栏的上一篇讨论了使用 JAXB API 生成类。本文主要讨论如何使用这些类,并分析 JAXB 的往返能力。您将了解从 XML 转换成 Java 代码然后再返回的过程中问题会出在哪儿。


标记本文!
发布日期: 2004 年 7 月 01 日
级别: 初级
访问情况 628 次浏览
建议: 0 (添加评论)

  平均分 (共 0 个评分 )
数据绑定 API 允许通过编程操纵 XML,从这一点上说它非常有用。输入 someElement.addAttribute("name", "value"); 要比解析文件、缓冲输出、添加组成属性声明的字符、关闭流和刷新输出流容易得多。但是如果不能正确地把变动写回文件,所有这些操纵就没有多少用处。本文重点讨论数据绑定世界中所谓的 编组(marshalling)过程,特别是 JAXB 的编组能力。具体来说,您将了解 JAXB 如何在往返的舞台上取得成功。

回顾

本专栏的 第一篇中,您已经了解一些重要的术语: 编组和 解组(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 作为输入文件。该文件会使生活轻松许多,但愿您喜欢它!


分享到:
评论

相关推荐

    JAXB的安装包及插件

    **JAXB(Java Architecture for XML Binding)** 是Java平台中用于XML到Java对象绑定的API,它是Java EE和Java SE标准的一部分,允许开发者在Java应用程序中方便地将XML数据转换为Java对象,反之亦然。这个过程极大...

    深入解析:Java中JAXB(Java Architecture for XML Binding)实现机制

    JAXB,即Java Architecture for XML Binding,是Java EE的一部分,提供了一种将XML数据结构化为Java对象的机制,以及反向的绑定过程。本文将深入探讨JAXB的实现原理、使用方法和最佳实践。 JAXB为Java开发者提供了一...

    数据绑定之JAXB

    JAXB(Java Architecture for XML Binding)是Java平台标准的一部分,用于实现这种数据绑定。JAXB允许开发者在Java类和XML文档之间进行自动的序列化和反序列化,极大地简化了XML处理。 在Java世界中,JAXB是处理XML...

    JAXB2 jaxb-api.jar jaxb-xjc.jar jaxb-impl.jar activation.jar

    JAXB2,全称为Java Architecture for XML Binding 2,是Java平台上的一个标准技术,用于在XML和Java对象之间进行绑定。它允许开发者通过简单的API将XML文档转换为Java对象,反之亦然,大大简化了XML数据处理。JAXB2...

    JAXB-2.2.6-release-documentation

    - **运行时绑定框架**:这部分详细介绍了如何在运行时使用 JAXB 进行数据绑定操作。 ### 知识点三:JAXB 2.2.6 发行说明 - **平台要求**:JAXB 2.2.6 需要在 Java 2 平台标准版 (J2SE) 上运行,具体版本依赖于...

    Java XML绑定技术 (Castor JAXB XMLBeans)

    虽然Castor最初并非专为XML绑定设计,但其提供的XML绑定功能仍然非常实用。 **特点:** - **支持旧版本JDK**:可以在JDK 1.3及更高版本上运行。 - **自动生成XML定义**:允许开发者通过定义Java Bean来生成XML定义...

    Java与XML数据绑定

    2. 使用JAXB进行数据绑定: - 编写Java类并添加必要的注解。 - 创建`Unmarshaller`实例,用于将XML解析为Java对象。 - 使用`Unmarshaller.unmarshal()`方法读取XML文件并生成Java对象。 - 创建`Marshaller`实例...

    jaxb-api-2.0.5.jar.zip

    2. **XJC (XML Java Compiler)**:是JAXB的一部分,用于从XML Schema生成Java类,实现XML到Java的绑定。 **与其他技术的配合**: JAXB通常与Java的其他XML处理技术一起使用,如StAX(Streaming API for XML)用于...

    jaxb2.3.0依赖jar.rar

    Java Architecture for XML Binding (JAXB) 是Java平台中用于XML到Java对象绑定的标准技术,它允许开发者在Java程序中直接操作XML数据,而无需编写大量的XML解析和序列化代码。JAXB 2.3.0是该技术的一个版本,包含了...

    jaxb-impl.jar包

    impl.jar`是Java Architecture for XML Binding (JAXB)的一个实现包,它是Java平台标准版(Java SE)和企业版(Java EE)的一部分,主要用于XML到Java对象的绑定以及反之,使得开发者能够方便地在Java程序中处理XML...

    最新JAXB解析XML教程

    **JAXB(Java Architecture for XML Binding)**是Java平台上的一个标准API,它允许开发者将XML文档和Java对象之间进行绑定,实现XML数据的编解码。JAXB为开发人员提供了一种简单、高效的方式,使得在Java应用程序中...

    JAXB资料.rar

    JAXB_2.2_API.chm,Java+XML绑定技术.doc JAXB_2.2_API.chm,Java+XML绑定技术.doc JAXB_2.2_API.chm,Java+XML绑定技术.doc JAXB_2.2_API.chm,Java+XML绑定技术.doc JAXB_2.2_API.chm,Java+XML绑定技术.doc JAXB_2.2_...

    jaxb-api jaxb-impl jar

    `jaxb-api`和`jaxb-impl`是JAXB框架的核心组成部分。这两个JAR文件在处理XML到Java对象的绑定过程中扮演着关键角色。 1. **jaxb-api.jar**: 这个库包含了JAXB API,即Java接口和抽象类,定义了JAXB的工作方式。它...

    JAXB的 eclipse插件

    3. **XML到Java对象的绑定**:通过JAXB,可以解析XML文档并创建相应的Java对象实例,这在处理XML输入数据时非常有用。 4. **源代码编辑器支持**:Eclipse的JAXB插件还提供了代码补全、错误检查和格式化等功能,使得...

    jaxb文件包

    JAXB(Java Architecture for XML Binding)是Java平台上的一项标准技术,用于将XML文档与Java对象之间进行绑定,以便于XML数据的处理。JAXB提供了一种自动的方式,将XML Schema定义的数据模型转换为Java类,同时也...

    jaxb (XML操作)

    2. **实例化(Unmarshalling)**:当需要将XML数据转换为Java对象时,JAXB使用Unmarshaller接口解析XML文档,生成对应的Java对象。这个过程是将XML数据"反序列化"为可操作的Java对象。 3. **序列化(Marshalling)*...

    jaxb:这是jaxb项目的最终版本

    在本篇文章中,我们将深入探讨JAXB的工作原理、使用场景以及如何通过Maven集成和应用。 **1. JAXB工作原理** JAXB的核心在于将XML Schema(XSD)文件转换为Java类,这一过程称为编译或绑定。反过来,JAXB也可以将...

    jaxb-svg11-1.0.2-API文档-中英对照版.zip

    赠送jar包:jaxb-svg11-1.0.2.jar; 赠送原API文档:jaxb-svg11-1.0.2-javadoc.jar; 赠送源代码:jaxb-svg11-1.0.2-sources.jar; 赠送Maven依赖信息文件:jaxb-svg11-1.0.2.pom; 包含翻译后的API文档:jaxb-svg11...

    activation.jar jaxb1-impl.jar jaxb-api.jar jaxb-impl.jar jaxb-xjc.jar jsr173_1.0

    它是JAXB规范的一部分,定义了如何将Java类与XML Schema绑定,以及如何在Java代码中生成和解析XML文档。 4. **jaxb-impl.jar**:这是JAXB的实现,提供了API中的具体实现,包括了序列化和反序列化功能。它通常与jaxb...

Global site tag (gtag.js) - Google Analytics