XML and the Java API for XML Binding (JAXB)


We have already discussed JAXP in detail and seen how JAXP supports SAX and DOM. JAXB is another way of processing XML through Java classes, and therefore provides all the features that SAX and DOM provide. JAXB features a newer approach, and an easier way of authoring and processing XML compared to SAX or DOM. You can generate Java classes directly from the XML DTD that you want to author or process. The following are the steps to accomplish this:

  1. Take the DTD of the XML that you want to author or process through Java classes. DTDs are a way to describe the structure of XML documents. The latest way of describing XML structures is to use XSD (XML Schema Definition) files. However, JAXB currently only supports DTDs. Support for XSDs can be expected in the future.

  2. Write the JAXB binding schema. This schema allows you to customize Java classes that will be produced. For example, you can customize names of packages, classes, and methods. You can also decide the data type of return values from methods of Java classes. We'll give examples of doing this in the section "Writing the Binding Schema for JAXB." However, if you don't want to customize the creation of Java classes, you can leave it to the JAXB Schema Compiler to assume default behavior.

  3. Provide the DTD from the first step and the binding schema from the second step to the JAXB Schema Compiler provided with Sun's implementation. The Compiler will generate the required Java class for you.

  4. Java classes generated by the Schema Compiler use the packages provided by Sun in the reference implementation for JAXB. As a last step before you can use these newly generated Java classes, you will need to set the classpath to include all JAXB-related classes.

JAXB-generated classes are normally more efficient and require a smaller footprint in memory compared to using SAX and DOM. This is because Java classes generated by the JAXB Schema Compiler are custom-built for your specific DTD.

We will now give a step-by-step illustration of the previously mentioned steps using a sample XML structure.

Step 1: DTD

The following is a sample DTD that we'll take in our sample JAXB application. (We are not discussing P2P in this section, but JAXB is expected to have an important role in developing P2P applications. Therefore, the DTD that we have chosen for our sample application belongs to one of the JXTA specifications. JXTA uses this DTD to define the structure of search requests issued by peers.)

 <?xml version="1.0" encoding="UTF-8"?>  <!ELEMENT request (query)> <!ELEMENT query (author+, title)> <!ELEMENT author (quote)> <!ELEMENT title (#PCDATA)> <!ELEMENT quote (#PCDATA)> <!ATTLIST request        id CDATA #REQUIRED        query-space CDATA #REQUIRED > 

This sample DTD contains five elements: request, query, author, quote, and title. The request element contains a query element. The query element contains one or more (+ sign) author elements and exactly one title element. The author element contains one quote element, which in turn contains only PCDATA (Parsed Character DATA, which generally means content with escape character sequences such as &lt; for <). The title element also contains only PCDATA. The request element contains the two attributes id and query-space.

For the sake of clarity, the following is a valid XML file that conforms to the preceding DTD:

 <?xml version="1.0" ?>  <request docEmphStrong">1C8DAC3036A911D584BCC2C23" query-space="http://bigbookseller.com/js"> <query> <author> <quote>Muhammad Imran</quote> </author> <author> <quote>Bilal Siddiqui</quote> </author> <title>Java</title> </query> </request> 

Step 2: Writing the Binding Schema

We will now demonstrate the authoring of binding schema, which enables you to specify exactly how you would like your Java classes to behave. Look at the following binding schema:

 <xml-java-binding-schema version="1.0-ea">  <element name="request" type = "class" root="true" /> <element name="query" type="class" root="true" /> </xml-java-binding-schema> 

This binding schema is itself an XML file. The first tag is <xml-java-binding-schema>, which specifies the version of JAXB specification that you're working with. Next is an empty <element/> tag with several attributes.

The name attribute refers to the root element of our DTD (the request element). This line of the binding schema simply says "The request element in your DTD should be handled by a separate Java class." When you compile the DTD and binding schema together in the next step to generate Java classes, you will see that there is a separate Java class named Request that handles the authoring and processing of the request element.

Similarly, the third line of the binding schema says that we also want a separate Java class to handle the query element.

Step 3: Compiling the DTD and Binding Schema Together into a Set of Java Classes

We are now ready to run the Schema Compiler and generate the required Java classes. Execute the Compiler with the following command:

 Java com.sun.tools.xjc.Main Search.DTD search1.xjs  

Notice that name of our DTD file is search.DTD, and name of the binding schema file is search1.xjc. You will need to save these files in your current working folder before you can compile them. Moreover, the JAXB compiler should be in your classpath (jaxb-xjc-1.0-ea.jar for the early-access release version 1.0).

This command will generate the following set of classes:

  • Request.java

  • Query.java

  • Author.java

Have a look at Request.java. We have not included these Java files in this chapter, but you can either generate them yourself using the Schema Compiler as described previously, or download the files from this book's accompanying Web site. The following is a code extract from the Request.java class that specifies the private variable declarations for the class:

 private String _Id;  private String _QuerySpace; private Query _Query; 

Here we have two strings _Id and _QuerySpace that will hold the attribute values of id and queryspace for our Request.Java class.

There is another private data member named _Query that's an object of the Query class. Query.java is another file generated by the Schema Compiler that corresponds to the query element in our DTD. Recall from the discussion in step 1 that the request element in our DTD can contain only one query. This is reflected in the Java file generated by the Schema Compiler.

We also have the public methods setQuery and getQuery. The setQuery method takes a Query object and places it in the private data member _Query. On the other hand, the getQuery() method returns the Query object from the internal data structure. The following is the simple code for the getQuery() method:

 public Query getQuery() {          return _Query;     } 

Similarly, the Query class will hold its own data members. But why do we have an Author class while we specified to have separate classes only for the request and query elements in the binding schema in Step 2? The reason for having a separate Author class is that there can be more than one author elements inside a query element (refer to the DTD of Step 1). Therefore, the Query class will have to maintain a list of author elements. JAXB accomplishes this by defining a separate Author class, so that Query can maintain a list of all Author objects (one Author object for each author element).

We will shortly describe how to use these Java classes, but first we have to set the classpath.

Step 4: Setting the Classpath for the Newly Generated Classes

In order to use the Java classes generated by the JAXB Schema Compiler, you need to set the classpath for the following two JAR files:

  • jaxb-xjc-1.0-ea.jar

  • jaxb-rt-1.0-ea.jar

The three Java classes that we generated in Step 3 use packages included in these JAR files. Therefore, you should have these JARs in your classpath. Once you have set the correct classpath, you can compile your Java classes as normal Java files.

Using JAXB Classes in a Java Application

We will now demonstrate how to use the newly generated Java classes in a Java application. Look at the following lines of code:

 InputStream ins = new FileInputStream( new File("SearchInput.xml"));  Request request = Request.unmarshal(ins); OutputStream outs = new FileOutputStream( new File ("SearchOutput.xml")); request.marshal(outs); 

These four lines of code demonstrate two important functions called unmarshaling and marshaling.

The first line creates an InputStream over an XML file named SearchInput.xml. You can use the XML file of Step 1 for this purpose. The second line calls the static method unmarshal() of the Request class and passes the InputStream to it. This unmarshal() method will internally parse the XML stream, load it into a Request object, and return the loaded Request object. We have stored the reference of the returned Request object in a variable. This process is called unmarshaling, in which an XML stream is loaded into Java objects.

The third and fourth lines of code demonstrate the reverse of unmarshaling, called marshaling. Here we take an OutputStream over a file named SearchOutput.xml and pass it to the marshal() method of the same Request object that we obtained through unmarshaling in the previous paragraph. The marshal() method will write the Java object as an XML stream to the OutputStream supplied to it. Therefore, marshaling is the process in which Java objects are converted into XML streams.

After the execution of these four lines of code, the two XML files SearchInput.xml and SearchOutput.xml should match with each other.

In some real-world applications, you will be required to unmarshal an XML stream and edit it before marshaling it back to an XML stream. For such applications, you will use the set and get methods of the Java classes that we explained in Step 3 to edit the XML data.



JavaT P2P Unleashed
JavaT P2P Unleashed
ISBN: N/A
EAN: N/A
Year: 2002
Pages: 209

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net