跳转到主要内容

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

当您初次登录到 developerWorks 时,将会为您创建一份概要信息。您在 developerWorks 概要信息中选择公开的信息将公开显示给其他人,但您可以随时修改这些信息的显示状态。您的姓名(除非选择隐藏)和昵称将和您在 developerWorks 发布的内容一同显示。

所有提交的信息确保安全。

  • 关闭 [x]

当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

所有提交的信息确保安全。

  • 关闭 [x]

实用数据绑定: 使用 JaxMe 转换 XML

编组和解组

Brett McLaughlin (brett@newInstance.com), 作家/编辑, O'Reilly Media, Inc.
Brett McLaughlin 从 Logo 时代(还记得那个小三角吗?)就开始从事计算机。最近几年,他已经成为 Java 技术和 XML 社区最知名的作家和程序员之一。他曾经在 Nextel Communications 实现过复杂的企业系统,在 Lutris Technologies 实际编写应用程序服务器,最近又在 O'Reilly Media, Inc. 继续撰写和编辑这方面的书籍。他的新著 Java 1.5 Tiger: A Developer's Notebook是关于新版本 Java 技术的第一本参考书,经典巨著 Java and XML仍然是在 Java 技术中使用 XML 技术的权威参考。

简介: 在上一篇文章中,Brett 帮助您对 JaxMe API 有了深入的了解。在这一基础上,本文将说明如何将 XML 文档转化成 Java 类实例、操纵底层的 XML 数据然后再把修改后的数据转换成 XML。本文将为您提供翔实的 JaxMe 应用知识,以便在您的应用程序编写中加以运用。

发布日期: 2004 年 9 月 01 日
级别: 中级
访问情况 : 907 次浏览
评论: 


首先要指出我希望您已经读过本系列文章的 上一篇,事实上我将沿用那篇文章中的例子,如果您没有按照顺序阅读可能会有点手足无措。

迭代的过程

本文将指出数据绑定的迭代特性,这也是您需要真正注意的一点。很多 API,特别是那些属于 工具类的 API,都只需要放入类路径然后直接使用即可,Jakarta Commons 类就是一个很好的例子。就是说只要放到 Java 工具组中就随时都可以使用。但事实上,数据绑定 API 的工作方式有点不同,人们很少会到处使用数据绑定中的方法,而是在应用程序的某一部分集中使用数据绑定。

为了强调这一点,这些文章就是按照人们编写代码的方式写成的。上一篇文章中我给出了一个简单的 XML 模式,并假设有两个实体以此作为相互通信的标准。这两个实体可以是公司、同一公司内的不同部门,也可以是两个应用程序组件。无论哪种情况,都使用 JaxMe 从该模式生成类,这些类然后大概被交给 Java 开发人员。通过 XML 模式的这种 Java 表示,就可以将符合那种模式的 XML 文档转化到 Java 类,或者相反。

再重复一次

我相信有些读者一直坚持阅读本专栏,对于数据绑定是什么的议论听到过不下十次。但是,每个月都有不少新手写信告诉我,他们正在努力弄明白这些东西。请原谅我的罗嗦吧,也许您旁边的那个人正在学习呢,多重复一遍说不定能让您的日子好过一点!


赶上进度

首先我们来回顾上一篇文章中用于生成类的模式,如清单 1 所示。


清单 1. 用于学生的 XML Schema
<?xml version="1.0" encoding="UTF-8"?>
<schema attributeFormDefault="unqualified" 
        elementFormDefault="qualified" 
        targetNamespace="http://dw.ibm.com/jaxme/student" 
        xml:lang="EN" 
        xmlns:stu="http://dw.ibm.com/jaxme/student" 
        xmlns="http://www.w3.org/2001/XMLSchema"
> 
  <element name="students">
    <complexType>
      <sequence>
        <element name="student" maxOccurs="unbounded" 
           type="stu:Student" />
        <element name="college" minOccurs="0" 
           maxOccurs="unbounded" type="stu:College" />
      </sequence>
    </complexType>
  </element>
  <complexType name="Student"> 
    <sequence> 
      <element name="firstName" type="string" /> 
      <element name="lastName" type="string" /> 
      <element name="collegeId" type="string" />
      <element maxOccurs="unbounded" name="address" 
         type="stu:Address" />
    </sequence> 
  </complexType> 
  <complexType name="Address"> 
    <sequence> 
      <element name="street" type="string" /> 
      <element name="city" type="string" /> 
      <element name="state" type="string" /> 
      <element name="zip" type="positiveInteger" /> 
    </sequence> 
    <attribute name="type" type="string" use="required" />
  </complexType> 
  <complexType name="College"> 
    <sequence> 
      <element name="name" type="string" /> 
      <element name="address" type="stu:Address" />
    </sequence>
    <attribute name="id" type="string" use="required" />
  </complexType> 
</schema>

有了这个模式之后就可以处理它的实例文档,如清单 2 所示。


清单 2. 基本的学生列表
<?xml version="1.0" encoding="UTF-8"?>
<students
  xmlns="http://dw.ibm.com/jaxme/student"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://dw.ibm.com/jaxme/student student.xsd"
>
  <student>
    <firstName>Brett</firstName>
    <lastName>McLaughlin</lastName>
    <collegeId>LBU</collegeId>
    <address type="home">
      <street>1029 Burlingham</street>
      <city>Waco</city>
      <state>TX</state>
      <zip>87610</zip>
    </address>
  </student>
  <student>
    <firstName>Gary</firstName>
    <lastName>Greathouse</lastName>
    <collegeId>LBU</collegeId>
    <address type="home">
      <street>9098 Townhall Drive</street>
      <city>Waco</city>
      <state>TX</state>
      <zip>87621</zip>
    </address>
  </student>
  <college id="LBU">
    <name>Louisiana Baptist University</name>
    <address type="home">
      <street>6301 Westport Avenue</street>
      <city>Shreveport</city>
      <state>LA</state>
      <zip>71129</zip>
    </address>
  </college>
</students>

我分别把这两个文件命名为 students.xsdstudent1.xml。本文中将读取 student1.xml,打印其中的一些信息,增加和改变一些信息,然后将修改的数据序列化为一个新的文件 student2.xml。任务非常简单,但是涉及到了使用 JaxMe 进行基本的数据绑定所需要了解的大部分知识。


把 XML 转化为 Java 代码

第一步是把这个 XML 文件转化为 Java 表示。 上一篇 文章的 com.ibm.dw.jaxme.student 包提供了我们需要的类。现在要做的就是读入 XML 文件,告诉 JaxMe 用什么类表示文件中的对象,让数据绑定 API 完成它们的工作。清单 3 是一个完成这项工作的例子,先看一遍,后面有详细的说明。


清单 3. 读取并打印 student1.xml
package com.ibm.dw.jaxme.example;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
// JAXB classes
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
// SAX classes
import org.xml.sax.InputSource;
// Generated classes
import com.ibm.dw.jaxme.student.*;
public class JaxMeTester {
  /** Input XML File */
  private File inputFile;
  public JaxMeTester(String inputFilename) {
    this.inputFile = new File(inputFilename);
  }
  public Students readXML() throws IOException, JAXBException {
    // Get a handle to the input file
    InputSource source = 
      new InputSource(new FileInputStream(inputFile));
    source.setSystemId(inputFile.toURL().toString());
    // Parse
    JAXBContext ctx = JAXBContext.newInstance(
      "com.ibm.dw.jaxme.student");
    Unmarshaller u = ctx.createUnmarshaller();
    return (Students)u.unmarshal(source);
  }
  public void printStudents(Students students, PrintStream out) throws IOException {
    // Get a map of college IDs and names
    Map colleges = new HashMap();
    List list = students.getCollege();
    for (Iterator i = list.iterator(); i.hasNext(); ) {
      College college = (College)i.next();
      colleges.put(college.getId(), college.getName());
    }
    out.print("\n\n--- Student Listings ---\n\n");
    list = students.getStudent();
    for (Iterator i = list.iterator(); i.hasNext(); ) {
      Student student = (Student)i.next();
      out.println("Name: " + student.getFirstName() + " " + student.getLastName());
      List addresses = student.getAddress();
      for (Iterator j = addresses.iterator(); j.hasNext(); ) {
        Address address = (Address)j.next();
        printAddress(address, out);
      }
      out.println("College: " + colleges.get(student.getCollegeId()));
      out.println();
    }
    list = students.getCollege();
    for (Iterator i = list.iterator(); i.hasNext(); ) {
      College college = (College)i.next();
      out.println("Name: " + college.getName());
      out.println("Address: ");
      printAddress(college.getAddress(), out);
      out.println();
    }
  }
  private void printAddress(Address address, PrintStream out) throws IOException {
    out.print("     " + address.getStreet() + "\n");
    out.print("     " + address.getCity() + ", " + address.getState() + "     " +
              address.getZip() + "\n");
  }
  public static void main(String[] args) {
    if (args.length < 1) {
      System.err.println("Incorrect arguments supplied!");
      System.err.println("Usage: java com.ibm.dw.jaxme.example.JaxMeTester " +
                         "[input XML filename]");
      return;
    }
    try {
      JaxMeTester tester = new JaxMeTester(args[0]);
      Students students = tester.readXML();
      tester.printStudents(students, System.out);
    } catch (Exception e) {
      System.err.println("Error occurred: " + e.getMessage());
      e.printStackTrace(System.err);
    }
  }
}

设置输入文件

首先要将 XML 输入文件变为 JaxMe(以及底层的 SAX 解析器)能够使用的形式。显然应该选择 SAX 的 InputSource 类,这是文件、流以及您能够想到的任何东西的统一输入格式。清单 4 中的内容是从上例中摘出来的,可以看到 JaxMeTester 所接受的 String 文件名被转化为 InputSource (包括几个中间步骤)。


清单 4. 将输入文件转化为 InputSource
  /** Input XML File */
  private File inputFile;
  public JaxMeTester(String inputFilename) {
            this.inputFile = new File(inputFilename);
  }
  public Students readXML() throws IOException, JAXBException {
    // Get a handle to the input file
        
    InputSource source = 
      new InputSource(new FileInputStream(inputFile));
    source.setSystemId(inputFile.toURL().toString());
    // Parse
  }
      

如果您恰好熟悉 SAX,没有什么特别值得注意的地方。惟一需要指出的是 File 的使用,这里没有直接传递 String 。虽然可以采用后一种方法,但是这样做就没有 Java 语言 File 类所提供的保护了。事实上, InputSource 在构造函数中做的第一件事就是将 String 转化为 File ,这正是我们要做的。此外,这种方法很容易设置输入文件的系统 ID,如果直接使用 String 而不是对象就麻烦得多了。

设置 JaxMe

接下来要设置 JaxMe 解组,只需要一行代码,如清单 5 所示。这里要告诉 JAXB 上下文(要记住 JaxMe 是 JAXB 的一种实现,因此常常使用这种语义)到哪里寻找 jaxb.properties文件。我总是将其放在与相关类相同的目录中,就是说只要使用生成类的包名就可以了。


清单 5. 告诉 JaxMe 到哪里寻找属性文件
    JAXBContext ctx = JAXBContext.newInstance(
      "com.ibm.dw.jaxme.student");

该文件本身只有一行,如清单 6 所示,它告诉 JAXB 要加载哪一种数据绑定上下文实现。


清单 6. jaxb.properties 文件
javax.xml.bind.context.factory=org.apache.ws.jaxme.impl.JAXBContextImpl

这里值得一提的是代码中 没有JaxMe 专用的类。虽然必须将 JaxMe 放在类路径中,但 JAXB 从这个属性文件中获得所有 JaxMe 专用的信息。换句话说,不用改变代码就可以从 JAXB 的参考实现切换为 JaxMe(强烈建议使用)。

解组

建立了 JAXB 上下文之后,将 XML 文件转化为 Java 表示很容易,如清单 7 所示,这些细节没有吸引人的地方。


清单 7. 解组 XML
  public Students readXML() throws IOException, JAXBException {
    // Get a handle to the input file
    InputSource source = 
      new InputSource(new FileInputStream(inputFile));
    source.setSystemId(inputFile.toURL().toString());
    // Parse
    JAXBContext ctx = JAXBContext.newInstance(
      "com.ibm.dw.jaxme.student");
    
        Unmarshaller u = ctx.createUnmarshaller();
    return (Students)u.unmarshal(source);
  }
      

当然,这段代码非常令人厌烦,但正因如此也就显得很棒;这仅仅是 劳动,就您而言不用花费多少心思。

处理 XML

一旦获得 Students 对象,也就完成了这个练习中的数据绑定部分。 printStudents() 方法可以说明这一点,因为它根本不知道 JAXB 或者 JaxMe 的存在。事实上也可以在不同的类中(甚至非 Java 语言模块中),没有任何问题。这里不再重复列出代码,只不过是 Java 对象的一些打印调用。

程序的输出

您可以运行 JaxMeTester 并提供前面的 XML 输入文件来测试这些代码。该程序将会折腾上一秒钟,然后输出与清单 8 类似的结果。这是最漂亮的打印工作,但是应该让您明白使用 JaxMe 读 XML 文件是多么简单。


清单 8. 程序对 student1.xml 的输出结果
test:
     [java] --- Student Listings ---
     [java] Name: Brett McLaughlin
     [java]      1029 Burlingham
     [java]      Waco, TX     87610
     [java] College: Louisiana Baptist University
     [java] Name: Gary Greathouse
     [java]      9098 Townhall Drive
     [java]      Waco, TX     87621
     [java] College: Louisiana Baptist University
     [java] Name: Louisiana Baptist University
     [java] Address:
     [java]      6301 Westport Avenue
     [java]      Shreveport, LA     71129
BUILD SUCCESSFUL
Total time: 3 seconds

转向 Ant

与以前的文章一样,我使用 Ant 完成编译、运行和其他大部分工作。上一篇文章中已经详细介绍了 Ant 的用法,因此这里只需要引入构建文件( build.xml)就可以了。默认的目标包括生成类、编译生成的示例类并运行该例子,因此您只需要修改几个路径并输入 ant 就可以了。


使用数据

您可能已经猜到,一旦转化成 Java 形式这些数据的使用就非常简单了。而且这些操作同样与 JaxMe 毫无关系。因此我只给出一些代码,这些代码增加一所新的学院并改变一直处理的学校,代码的功能您可以自己分析,新增的方法如清单 9 所示。


清单 9. 在内存中修改学生信息
  public void modifyStudents(Students students) {
    // Add a college
    College college = new com.ibm.dw.jaxme.student.impl.CollegeImpl();
    college.setName("Norris Bible Baptist Seminary");
    college.setId("NBBS");
    Address address = new com.ibm.dw.jaxme.student.impl.AddressImpl();
    address.setStreet("724 North Jim Wright Freeway");
    address.setCity("Ft. Worth");
    address.setState("TX");
    address.setZip(new java.math.BigInteger("76108"));
    college.setAddress(address);
    // Add the college in
    List colleges = students.getCollege();
    colleges.add(college);
    // Change a student's college
    List list = students.getStudent();
    for (Iterator i = list.iterator(); i.hasNext(); ) {
      Student student = (Student)i.next();
      if (student.getFirstName().equals("Brett") &&
          student.getLastName().equals("McLaughlin")) {
        student.setCollegeId("NBBS");
      }
    }
  }

代码主体中还增加了一些额外的打印语句,如清单 10 所示。


清单 10. 其他的打印语句
  public static void main(String[] args) {
    if (args.length < 1) {
      System.err.println("Incorrect arguments supplied!");
      System.err.println("Usage: java com.ibm.dw.jaxme.example.JaxMeTester " +
                         "[input XML filename]");
      return;
    }
    try {
      JaxMeTester tester = new JaxMeTester(args[0]);
      Students students = tester.readXML();
      
        System.out.println("Students after reading in from disk...");
      tester.printStudents(students, System.out);
        
      tester.modifyStudents(students);
      System.out.println("\n\nStudents after in-memory modifications...");
      tester.printStudents(students, System.out);
    } catch (Exception e) {
      System.err.println("Error occurred: " + e.getMessage());
      e.printStackTrace(System.err);
    }
  }
      

输出结果如清单 11 所示,其中仅列出了学生清单修改 的结果。


清单 11. 修改后的打印输出
     [java] --- Student Listings ---
     [java] Name: Brett McLaughlin
     [java]      1029 Burlingham
     [java]      Waco, TX     87610
     [java] College: Norris Bible Baptist Seminary
     [java] Name: Gary Greathouse
     [java]      9098 Townhall Drive
     [java]      Waco, TX     87621
     [java] College: Louisiana Baptist University
     [java] Name: Louisiana Baptist University
     [java] Address:
     [java]      6301 Westport Avenue
     [java]      Shreveport, LA     71129
     [java] Name: Norris Bible Baptist Seminary
     [java] Address:
     [java]      724 North Jim Wright Freeway
     [java]      Ft. Worth, TX     76108

对于多数读者而言这都是些老生常谈,但对于刚接触数据绑定的读者而言,让我强调一下这一小段代码的重要意义。它说明您不需要 将 XML 作为 XML处理。事实上,除了将您带入数据绑定的大门之外,Java 代码一直在完成其他所有工作。虽然 SAX 和 DOM(以及 JDOM、dom4j 等等)很重要,而且对于底层系统可以说至关重要,但一般的 Java 程序员不再需要了解这些东西了。

Java 程序员可以编写接收和输出基本 Java 对象的所有方法,不论这些对象来自何处去向何方。就像良好的数据库代码把数据库交互和普通程序员分隔开一样,数据绑定也能做到。一旦某个方法不再使用对象,它就不需要知道信息是否被保存,当然也不需要知道信息是 如何保存的。这正是数据绑定的优美之处!


从 Java 转化到 XML

现在要将修改后的列表再保存到 XML 中。虽然可以覆盖原来的 student1.xml 文件,但是我更喜欢写入一个新的文件(从而可以比较异同)student2.xml。为此需要稍微修改 main() 方法,如清单 12 所示。


清单 12. 增加第二个参数作为输出文件名
 public static void main(String[] args) {
  if (
        args.length < 2) {
   System.err.println("Incorrect arguments supplied!");
   
        System.err.println("Usage: java com.ibm.dw.jaxme.example.JaxMeTester " +
                      "[input XML filename] [output XML filename]");
   return;
  }
  try {
   JaxMeTester tester = new JaxMeTester(args[0]);
   Students students = tester.readXML();
   System.out.println("Students after reading in from disk...");
   tester.printStudents(students, System.out);
   tester.modifyStudents(students);
   System.out.println("\n\nStudents after in-memory modifications...");
   tester.printStudents(students, System.out);
   
        tester.writeStudents(students, args[1]);
  } catch (Exception e) {
   System.err.println("Error occurred: " + e.getMessage());
   e.printStackTrace(System.err);
  }
 }
      

增加序列化代码

现在剩下的只有新的 writeStudents() 方法了,这个方法如此简单,我找不到任何理由来进一步解释,如清单 13 所示。


清单 13. 序列化 XML
  public void writeStudents(Students students, String outputFile) 
    throws IOException, JAXBException {
    // Serialize
    JAXBContext ctx = JAXBContext.newInstance(
      "com.ibm.dw.jaxme.student");
    Marshaller m = ctx.createMarshaller();
    FileWriter writer = new FileWriter(outputFile);
    m.marshal(students, writer);
    writer.close();
  }

丢失的 import 语句

现在还需要增加几个 import 语句。我不准备列出整个文件,但建议您下载本文的代码,其中包括完整的 JaxMeTester 源代码。

这些代码看起来与解组过程非常相似。通过 JAXB 创建了一个新的 Marshaller ,同样使用指定位置的 jaxb.properties 文件。然后将输出文件名包装在一个 writer 中,执行序列化并关闭 writer( 千万不要忘记关闭 writer!)。呜啦!编码、编译然后运行。

还记得“往返”吗?

结束之前让我们看一看输出文件(如果您使用了我给出的名称应该是 student2.xml),如清单 14 所示。


清单 14. student2.xml
<stu:students xmlns:stu="http://dw.ibm.com/jaxme/student">
  <stu:student>
    <stu:firstName>Brett</stu:firstName>
    <stu:lastName>McLaughlin</stu:lastName>
    <stu:collegeId>NBBS</stu:collegeId>
    <stu:address type="home">
      <stu:street>1029 Burlingham</stu:street>
      <stu:city>Waco</stu:city>
      <stu:state>TX</stu:state>
      <stu:zip>87610</stu:zip>
    </stu:address>
  </stu:student>
  <stu:student>
    <stu:firstName>Gary</stu:firstName>
    <stu:lastName>Greathouse</stu:lastName>
    <stu:collegeId>LBU</stu:collegeId>
    <stu:address type="home">
      <stu:street>9098 Townhall Drive</stu:street>
      <stu:city>Waco</stu:city>
      <stu:state>TX</stu:state>
      <stu:zip>87621</stu:zip>
    </stu:address>
  </stu:student>
  <stu:college id="LBU">
    <stu:name>Louisiana Baptist University</stu:name>
    <stu:address type="home">
      <stu:street>6301 Westport Avenue</stu:street>
      <stu:city>Shreveport</stu:city>
      <stu:state>LA</stu:state>
      <stu:zip>71129</stu:zip>
    </stu:address>
  </stu:college>
  <stu:college id="NBBS">
    <stu:name>Norris Bible Baptist Seminary</stu:name>
    <stu:address>
      <stu:street>724 North Jim Wright Freeway</stu:street>
      <stu:city>Ft. Worth</stu:city>
      <stu:state>TX</stu:state>
      <stu:zip>76108</stu:zip>
    </stu:address>
  </stu:college>
</stu:students>

您马上就会注意到所有的元素都正确使用了名称空间,而这个名称空间用前缀 stu 给出。因此该文件在语义上与输入是等价的(当然包含了新增加的信息),虽然看起来非常不同。这需要回顾 本系列文章的第一篇中所讨论的问题 —— 往返,XML 允许这样做,如果不习惯的话可能会令您感到困惑。如果您完全迷惑了,请再读一读第一篇文章。但是在明确指出这种差别之前,我还不想结束本文。


再论工具 API

还记得前面对工具 API 的讨论吗?我曾经说过数据绑定和工具 API 不同。我希望您注意到了这句话,因为这一点非常重要。数据绑定 API(JaxMe 仅是其中之一)的不利之处是很容易弥漫到所有的代码中。我曾经见过一些项目,虽然采用的体系结构相对不错,但是数据绑定出现在所有能够想像得到的地方,并且有几个地方我 从来都没有想像过。结果如果需要修改代码,升级和 API 转换是完全不可能的,因为应用程序的很多部分必须重新实现、重新测试、重新部署。

作为一名程序员应尽量避免出现这种情况。按照经验法则,应用程序层次之间应保持 无关性而非 依赖性。为此,应使用数据绑定 API 隔离业务层和编组解组 XML 的代码之间的交互。可以增加一个数据绑定层,防止直接调用 JaxMe(或者 JAXB 以及所用的其他 API)。我曾经看到过各种各样的解决方案 —— 我自己也曾提出几种方法 —— 只要您愿意隔离这些代码。这意味着升级或者修改只影响到隔离的少量代码,应用程序的其他部分仍然可以运行。记住这一点,您就不会烦恼缠身了。


结束语

掌握了 JaxMe 的基本用法之后,下一篇文章将介绍该 API 较难的地方,分析 JaxMe 为什么比它的表兄弟 JAXB 提供了 更多的功能。具体来说,我将关注数据库支持,详细探讨如何使用 JaxMe 向数据库中插入数据,如 MySQL。然后如果时间和空间允许的话(只能希望),我还将说明同样的技术如何用于 XML 数据库。

再后面呢?只有我的想像力才知道。:)我确实有一些想法,不过您要坚持读下去才会知道到底是什么。到那时候希望能再看到您。


参考资料

关于作者

Brett McLaughlin 从 Logo 时代(还记得那个小三角吗?)就开始从事计算机。最近几年,他已经成为 Java 技术和 XML 社区最知名的作家和程序员之一。他曾经在 Nextel Communications 实现过复杂的企业系统,在 Lutris Technologies 实际编写应用程序服务器,最近又在 O'Reilly Media, Inc. 继续撰写和编辑这方面的书籍。他的新著 Java 1.5 Tiger: A Developer's Notebook是关于新版本 Java 技术的第一本参考书,经典巨著 Java and XML仍然是在 Java 技术中使用 XML 技术的权威参考。

关于报告滥用的帮助

报告滥用

谢谢! 此内容已经标识给管理员注意。


关于报告滥用的帮助

报告滥用

报告滥用提交失败。 请稍后重试。


developerWorks:登录


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 使用条款

 


当您初次登录到 developerWorks 时,将会为您创建一份概要信息。您在 developerWorks 概要信息中选择公开的信息将公开显示给其他人,但您可以随时修改这些信息的显示状态。您的姓名(除非选择隐藏)和昵称将和您在 developerWorks 发布的内容一同显示。

请选择您的昵称:

当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

(长度在 3 至 31 个字符之间)


单击提交则表示您同意developerWorks 的条款和条件。 使用条款.

 


为本文评分

评论

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=XML
ArticleID=23131
ArticleTitle=实用数据绑定: 使用 JaxMe 转换 XML
publish-date=09012004
author1-email=brett@newInstance.com
author1-email-cc=dwxed@us.ibm.com

标签

Help
使用 搜索 文本框在 My developerWorks 中查找包含该标签的所有内容。

使用 滑动条 调节标签的数量。

热门标签 显示了特定专区最受欢迎的标签(例如 Java technology,Linux,WebSphere)。

我的标签 显示了特定专区您标记的标签(例如 Java technology,Linux,WebSphere)。

使用搜索文本框在 My developerWorks 中查找包含该标签的所有内容。热门标签 显示了特定专区最受欢迎的标签(例如 Java technology,Linux,WebSphere)。我的标签 显示了特定专区您标记的标签(例如 Java technology,Linux,WebSphere)。