Skip navigation.

Using XMLBeans in Web Service Clients and User Interfaces

by Steve Hanson
05/24/2004

Introduction

Web services leverage the power of XML to move complex data between disparate applications. But if your Web service client cannot understand XML documents, you have lost one of the principal advantages of Web services. Enter XMLBeans; because XMLBeans are strongly typed, they help you get the most of the XML messages provided by Web services.

The article below is divided into two parts. First I will speak generally about XMLBeans; I will explain what XMLBeans are, how to create them, and how to use them in a Web service client and other applications. Second I will use XMLBeans in a real world example by leveraging their capabilities in a client for the Google Web service.
Download the author's files associated with this article


Part I: XMLBeans

What is an XMLBean?
An XMLBean is essentially a Java type for handling XML documents. But XMLBeans are different from traditional DOM and cursor-based APIs because of their rich type awareness. With traditional API parsers you walk the elements of the XML document more or less blindly, without an awareness of the rich structure of a particular XML document. Traditional parsers know parent, child, and sibling relationships within the XML, but that's about it. For example, a traditional parser might extract data in the following way. Given the following XML document:


        <books>
            <book>
                <title>Foo</title>
                <author>Foo Author</author>
            </book>
            <book>
                <title>Bar</title>
                <author>Bar Author</author>
            </book>
        </books>




A cursor-based parser might extract the data "Bar" as so:


  XmlCursor cursor = xmlDoc.newCursor();
  cursor.toFirstChild();                  // select the first <book>
  cursor.toNextSibling();                 // select the second <book>
  cursor.toFirstChild();                  // select the <title> of the second <book>
  String title = cursor.xmlText()         // extract "Bar" from the <title> element




But an XMLBean gives you a rich, type-aware API for walking the document. With an XMLBean you would extract the same data in the following way:


  String title = xmlDoc.getBooks().getBookArray()[1].getTitle();  
 



Type-awareness makes parsing much more predictable and the parsing code becomes much easier to maintain, if the output from the host Web service should ever change. You can also create and manipulate XML documents with XMLBeans. The following API calls:


        MyBooks doc = MyBooks.Factory.newInstance();
        BookArray bookArr = doc.addNewBooks();
        Book book = bookArr.addNewBook();
        book.setAuthor("David Flanagan");
        book.setTitle("Java in a Nutshell");




Creates the following XML document:


        <books>
            <book>
                <title>David Flanagan</title>
                <author>Java in a Nutshell</author>
            </book>
        </books>




XMLBeans are type-aware, or "strongly typed", because they are based on XML schemas; a given XMLBean is constructed to reflect the data types and shape-rules of the schema it is based on.

Creating an XMLBean
XMLBean classes are compiled from an XML schema file (XSD file). Upon compilation, the XMLBean is constructed to reflect the data types and shapes-rules contained within the schema. The resulting XMLBean is able to parse any instance XML document that conforms to the schema.

To create an XMLBean using BEA WebLogic Workshop 8.1, place a schema file within a schemas project and compile the project. The result is a set of XMLBean Java types with a rich API attached to each type. The following schema file, BookList.xsd, compiles into three XMLBean Java types: MyBooks, BookArray, and Book, each with a rich API attached for working with the data types.

BookList.xsd

<?xml version="1.0"?>
<xsd:schema xmlns="http://www.w3.org/2001/XMLSchema" 
    xmlns:typens="MySchema"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    targetNamespace="MySchema">

    <xsd:complexType name="myBooks">
        <xsd:all>
            <xsd:element name="books" type="typens:BookArray"/>
        </xsd:all>
    </xsd:complexType>
    
    <xsd:complexType name="BookArray">
        <xsd:sequence>
            <xsd:element name="book" type="typens:book" nillable="true" 
                        minOccurs="0" maxOccurs="unbounded"/>
        </xsd:sequence>
    </xsd:complexType>
    
    <xsd:complexType name="book">
        <xsd:all>
            <xsd:element name="title" type="xsd:string"/>
            <xsd:element name="author" type="xsd:string"/>
        </xsd:all>
    </xsd:complexType>

</xsd:schema>




The three Java types can be seen in the XMLBean class folder:

1

Using XMLBeans in Applications
Once you have compiled a schema into XMLBean classes, you can use the XMLBean classes to create and/or handle any XML documents that conform to the schema. This is an especially powerful technique to use in Web service applications, which traffic in SOAP XML documents. In the remainder of this section will describe how to use XMLBean classes (1) in a Web service and (2) in Web service clients. Throughout I will utilize the following simple XML schema, HelloWorld.xsd:

HelloWorld.xsd

<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="HelloWorldSchemaTypes">
        <xs:element name="HelloMessage" type="xs:string"/>
</xs:schema> 




To give you an idea of how simple this schema is, here are two XML documents that conform to the schema:


<HelloMessage>
    Hello, World!
</HelloMessage>

<HelloMessage>
    Hello, Moon!
</HelloMessage>




When HelloWorld.xsd is compiled, one XMLBean class is generated: helloWorldSchemaTypes.HelloMessage.

1

(1) Using XMLBeans in a Web Service
Inside a Web service, XMLBean classes are typically used to create new XML documents and return those documents from Web service methods. The basic process for using XMLBean classes to create new XML documents is as follows.

  1. Compose a schema file (.XSD file) that lays down the rules to which your XML documents will conform. The following document describes one way to accomplish this task: "How Do I: Generate Schema from an XML Instance Document?"
  2. Save the schema file in a schemas project.
  3. Compile the schemas project.
  4. Import the generated XMLBeans classes into your Web service.


            import mySchema.MyXMLBeanClass;
    



  5. Create and manipulate new XML documents by calling methods on the XMLBean classes. Create new instance documents through the Factory.newInstance(); method on each XMLBean class


      // Create a new XML document
      MyXMLBeanClass doc = MyXMLBeanClass.Factory.newInstance();
      

    //Modify the XML document doc.setText("My response message.");



  6. Pass the XMLBean type to clients through the Web service's methods and/or callbacks. (The corresponding XML document will be passed as the payload of the SOAP document.)

The following Web service uses the XMLBeans class HelloMessageDocument to construct XML documents per client request. import helloWorldSchemaTypes.HelloMessageDocument;


public class HelloWorld implements com.bea.jws.WebService
{ 
    /**
     * @common:operation
     */
    public HelloMessageDocument hello(String who)
    {
        // Create a new XML document
        HelloMessageDocument message = HelloMessageDocument.Factory.newInstance();
        
        // Modify the XML document
        message.setHelloMessage("Hello, " + who);
        
        return message;
    }
} 




If the client provides the parameter "World!", the Web service will construct the following XML document.




    <HelloMessage>
        Hello, World! 
    </HelloMessage>




Note that the Web service method returns an XMLBean type to its client: HelloMessageDocument. When a Web service returns an XMLBean type, the original schema (the schema that generated the XMLBean) is automatically provided in the Web service's WSDL file. This allows clients to the Web service to replicate the XMLBean classes on their end. This puts Web services and their clients on the same page in terms of data type.

(2) Using XMLBeans in Web Service Clients
In Web service clients, XMLBeans are typically used to parse, manipulate, and extract data from the SOAP XML documents returned by the Web service.

The basic process for parsing and extracting data from SOAP XML documents in Web service clients is as follows:

  1. Acquire a schema file (.XSD file) corresponding to the SOAP XML messages sent out by the host Web service. In some cases you can simply treat the Web service's WSDL file as a schema file (.XSD file). In these cases, you can save the WSDL to your schemas project and compile the XMLBean classes directly from the WSDL.

    1

    But in other cases, where the WSDL contains WSDL-specific type referencing syntax, you will have to acquire a schema file in some other way. One example of WSDL-specific syntax is the following reference to an array type:


          <xsd:attribute ref="soapenc:arrayType" wsdl:arrayType="typens:ResultElement[]"/>.
              



    If you cannot use the WSDL file directly to compile XMLBeans classes, the following document describes one way to create a schema file from an instance XML document: "How Do I: Generate Schema from an XML Instance Document?"
  2. Save the schema (or WSDL) file in a schemas project.
  3. Compile the schemas project.
  4. Import the XMLBeans classes into your Web service client.

    import mySchema.MyXMLBeanClass;
  5. Assuming that the SOAP XML messages sent from the Web service conform to your schema file, you can parse the SOAP messages into XMLBeans when they arrive from the host Web service.


          MyXMLBeanClass message = helloWorldControl.hello();
            


Part II: Using XMLBeans with the Google Web Service

Before proceeding, it is recommended that you download the Google software development kit and acquire a Google Web APIs license key. In order to make its search engine as widely available as possible, Google provides a Web service access point to its search engine. The WSDL file describes this Web service: http://api.google.com/GoogleSearch.wsdl. Through the Web service, any software that can process XML documents and communicate over the Internet can become a client to the Google Web service.

The application you build below will have the following architecture. The Web service control will handle the SOAP traffic with the Google Web service. It will also parse these SOAP documents into XMLBean form and pass them to the user-facing portion of the application, for further processing for display to the user.

1

A Sample SOAP Request/Response with the Google Web
The following shows a sample SOAP request/response exchange between the Web service control and the Google Web service. At a minimum, a request must contain two parameters: the query term(s) and the developers license key. In the following request, the query term supplied is "Plato" and the maximum number of results has been limited to two.

Call the method doGoogleSearch:


<SOAP-ENV:Envelope xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" 
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
    <SOAP-ENV:Body SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> 
        <ns:doGoogleSearch xmlns:ns="urn:GoogleSearch"> 
            <key xsi:type="xsd:string">xxxXXXxxxXXXxxxXXXxxx</key>
            <q xsi:type="xsd:string">Plato</q>
            <start xsi:type="xsd:int">0</start>
            <maxResults xsi:type="xsd:int">2</maxResults>
            <filter xsi:type="xsd:boolean">false</filter>
            <restrict xsi:type="xsd:string"></restrict>
            <safeSearch xsi:type="xsd:boolean">false</safeSearch>
            <lr xsi:type="xsd:string"></lr>
            <ie xsi:type="xsd:string"></ie>
            <oe xsi:type="xsd:string"></oe>
        </ns:doGoogleSearch>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>




Get the following SOAP response back:

The request above produces the following response document. As you can see the XML in the response document is fairly complex, which makes it a perfect candidate for processing by an XMLBean. But how do you acquire a schema that captures the data types inside of the response document? The following step-by-step instructions will show you how to acquire a schema and being parsing this response document.


<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:xsd="http://www.w3.org/1999/XMLSchema" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"> 
    <SOAP-ENV:Body> 
        <ns1:doGoogleSearchResponse SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" 
                xmlns:ns1="urn:GoogleSearch"> 
            <return xsi:type="ns1:GoogleSearchResult"> 
                <documentFiltering xsi:type="xsd:boolean">false</documentFiltering>
                <estimatedTotalResultsCount xsi:
                                type="xsd:int">743000</estimatedTotalResultsCount>
                <directoryCategories ns2:arrayType="ns1:DirectoryCategory[1]" 
                                xmlns:ns2="http://schemas.xmlsoap.org/soap/encoding
/" xsi:type="ns2:Array"> <item xsi:type="ns1:DirectoryCategory"> <specialEncoding xsi:type="xsd:string"></specialEncoding> <fullViewableName xsi:type="xsd:string"> Top/Society/Philosophy/Philosophers/Plato</fullViewableName> </item> </directoryCategories> <searchTime xsi:type="xsd:double">0.233717</searchTime> <resultElements ns3:arrayType="ns1:ResultElement[2]" xmlns:ns3="http://schemas.xmlsoap.org/soap/encoding /" xsi:type="ns3:Array"> <item xsi:type="ns1:ResultElement"> <cachedSize xsi:type="xsd:string">24k</cachedSize> <hostName xsi:type="xsd:string"></hostName> <snippet xsi:type="xsd:string"><b> Plato</b>. <b>...</b> Before giving details of <b>Plato's</b> life we will take a few moments<br> to discuss how definite the details are which we give below. <b>...</b> </snippet> <directoryCategory xsi:type="ns1:DirectoryCategory"> <specialEncoding xsi:type="xsd:string"></specialEncoding> <fullViewableName xsi:type="xsd:string">Top/Science/Math/History/People </fullViewableName> </directoryCategory> <relatedInformationPresent xsi:type="xsd:boolean">true< /relatedInformationPresent> <directoryTitle xsi:type="xsd:string"><b>Plato</b> (427-347 BC)</directoryTitle> <summary xsi:type="xsd:string">"... the reality which scientific thought is seeking must be expressible in mathematical terms, mathemati...</summary> <URLxsi:type="xsd:string">http://www-gap.dcs.st-and.ac.uk/~history/ Mathematicians/Plato.html </URL> <title xsi:type="xsd:string"><b>Plato</b></title> </item> <item xsi:type="ns1:ResultElement"> <cachedSize xsi:type="xsd:string">3k</cachedSize> <hostName xsi:type="xsd:string"></hostName> <snippet xsi:type="xsd:string">Stanford Encyclopedia of Philosophy. Edited by Edward N. Zalta Editorial<br> Information. [Link to the local table of contents] Table of Contents < b>...</b> </snippet> <directoryCategory xsi:type="ns1:DirectoryCategory"> <specialEncoding xsi:type="xsd:string"></specialEncoding> <fullViewableNamexsi:type="xsd:string"> Top/Society/Philosophy/Reference /Stanford_Encyclopedia_of_Philosophy </fullViewableName> </directoryCategory> <relatedInformationPresent xsi:type="xsd:boolean">true </relatedInformationPresent> <directoryTitle xsi:type="xsd:string">Stanford Encyclopedia of Philosophy </directoryTitle> <summary xsi:type="xsd:string">Online philosophy reference work, articles are authored and updated by experts in the field. Edited...</summary> <URL xsi:type="xsd:string">http://plato.stanford.edu/</URL> <title xsi:type="xsd:string">Stanford Encyclopedia of Philosophy</title> </item> </resultElements> <endIndex xsi:type="xsd:int">2</endIndex> <searchTips xsi:type="xsd:string"></searchTips> <searchComments xsi:type="xsd:string"></searchComments> <startIndex xsi:type="xsd:int">1</startIndex> <estimateIsExact xsi:type="xsd:boolean">false</estimateIsExact> <searchQuery xsi:type="xsd:string">Plato</searchQuery> </return> </ns1:doGoogleSearchResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope>



Step-By-Step Instructions

Step 1: Setup

In WebLogic Workshop, select File-->New-->Application

In the New Application dialog, in the right-hand pane, select Default Application. Complete the rest of the dialog according to your preferences.

Step 2: Create a Schema and XMLBeans Types for Google Search Results

In many cases, you can compile a Web service's WSDL to capture XMLBean versions of the Web service's data types: but the Google WSDL is not one of those cases.

You cannot compile XMLBean classes directly from the Google WSDL because it uses SOAP-specific syntax to refer to an array type (XMLBeans currently only support schema types):


      <xsd:complexType name="ResultElementArray">
        <xsd:complexContent>
          <xsd:restriction base="soapenc:Array">
             <xsd:attribute ref="soapenc:arrayType" 
                         wsdl:arrayType="typens:ResultElement[]"/>
          </xsd:restriction>
        </xsd:complexContent>
      </xsd:complexType>

      <xsd:complexType name="DirectoryCategoryArray">
        <xsd:complexContent>
          <xsd:restriction base="soapenc:Array">
             <xsd:attribute ref="soapenc:arrayType" 
                         wsdl:arrayType="typens:DirectoryCategory[]"/>
          </xsd:restriction>
        </xsd:complexContent>
      </xsd:complexType>




For this reason, you must construct a XML schema for the Google Web service that captures the data types returned by the service. The resulting XML schema file was created by examining the SOAP messages returned by the service and editing the original WSDL file accordingly.

GoogleSearch.xsd

<?xml version="1.0"?>
<!--
This schema describes data types returned by the Google Web 
service, based on the WSDL published at http://api.google.com/GoogleSearch.wsdl. --> <xsd:schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:typens="urn:GoogleSearch" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:GoogleSearch"> <xsd:complexType name="DirectoryCategory"> <xsd:all> <xsd:element name="fullViewableName" type="xsd:string"/> <xsd:element name="specialEncoding" type="xsd:string"/> </xsd:all> </xsd:complexType> <xsd:complexType name="DirectoryCategoryArray"> <xsd:sequence> <xsd:element name="DirectoryCategory" type="typens:DirectoryCategory" nillable="true" minOccurs="0" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> <xsd:complexType name="GoogleSearchResult"> <xsd:all> <xsd:element name="documentFiltering" type="xsd:boolean"/> <xsd:element name="searchComments" type="xsd:string"/> <xsd:element name="estimatedTotalResultsCount" type="xsd:int"/> <xsd:element name="estimateIsExact" type="xsd:boolean"/> <xsd:element name="resultElements" type="typens:ResultElementArray"/> <xsd:element name="searchQuery" type="xsd:string"/> <xsd:element name="startIndex" type="xsd:int"/> <xsd:element name="endIndex" type="xsd:int"/> <xsd:element name="searchTips" type="xsd:string"/> <xsd:element name="directoryCategories" type="typens:DirectoryCategoryArray"/> <xsd:element name="searchTime" type="xsd:double"/> </xsd:all> </xsd:complexType> <xsd:complexType name="item"> <xsd:all> <xsd:element name="summary" type="xsd:string"/> <xsd:element name="URL" type="xsd:string"/> <xsd:element name="snippet" type="xsd:string"/> <xsd:element name="title" type="xsd:string"/> <xsd:element name="cachedSize" type="xsd:string"/> <xsd:element name="relatedInformationPresent" type="xsd:boolean"/> <xsd:element name="hostName" type="xsd:string"/> <xsd:element name="directoryCategory" type="typens:DirectoryCategory"/> <xsd:element name="directoryTitle" type="xsd:string"/> </xsd:all> </xsd:complexType> <xsd:complexType name="ResultElementArray"> <xsd:sequence> <xsd:element name="item" type="typens:item" nillable="true" minOccurs="0" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> </xsd:schema>



When you save the schema file GoogleSearch.xsd in a schemas project and compile, the following five XMLBean class are produced:

1

Step 3: Generate a Web Service Control from the WSDL File

In this step you will automatically generate a Web service control file from the Web service WSDL file. A Web service control handles the SOAP traffic between your client and the Google Web service. It sends SOAP message requests to the Web service, listens for SOAP responses, and forwards them to the interface. In this step I will build a Web service that converts the SOAP messages into XMLBean types before it forwards them to the user interface.

Save the WSDL file (located at http://api.google.com/GoogleSearch.wsdl) within your Web application project.

Right-click the WSDL file and select Generate Service Control.

1

In the Generate field using XmlBean dialog, select Yes.

1

The Web service control file GoogleSearchControl.jcx is generated.

By selecting Yes, you are directing the methods of your Web service control to return XMLBeans types. For example, the following method from GoogleSearchControl.jcx returns an XMLBean type (GoogleSearchResult).


public googleSearch.GoogleSearchResult doGoogleSearch 
                (java.lang.String key,
                java.lang.String q, 
                int start, int maxResults, boolean filter, 
                java.lang.String restrict, boolean safeSearch, 
                java.lang.String lr, java.lang.String ie, 
                java.lang.String oe);




Step 4: Creating a User Interface
You now have a way to query the Google search engine and receive responses in the form of XMLBeans. The final step is to create a user interface that parses and displays those results in some useful, intuitive fashion. Whatever your user interface takes, because the search results are in XMLBean form, you have a rich API for extracting the relevant data.

For example, to print out all of the <title> elements, you would do the following:


        // Query the control method
        googleSearch.GoogleSearchResult results = 
                myControl.doGoogleSearch(...supply parameters here...);
        
        // Print out the URLs to the console
        for(int i = 0; i < results.getResultElements().getItemArray().length; i++)
        {
            System.out.println( results.getResultElements().getItemArray(i).getURL() );
        }




Databinding to XMLBeans from JSP Pages

You can also XMLBeans in conjunction with a JSP page. Using WebLogic Workshop's "databinding" technology you can refer to Java types from within a JSP page without placing Java code on the JSP page. This greatly aids in the task of separating code and UI in a Web application. But you also get the benefit of retaining type-awareness in your JSP pages because the JSP pages refer to the Java data (in another file) in a type-aware manner.

For example, suppose you have the following XMLBean data in a page flow file (a JAVA file with the JPF extension).

googleSearch.GoogleSearchResult results = myControl.doGoogleSearch(...supply parameters here...);

From a JSP page you could databind to this Java data using one of WebLogic Workshop's special databinding-capable tags. (These tags begin with the prefix "netui".)


        <netui:content value="{pageFlow.results.resultElements.itemArray[0].URL}" />




Notice that this JSP tag contains no Java code (the expression language used is ECMA script), but it retains Java type-awareness in the expression "pageFlow.results.resultElements.itemArray[0].URL".

Article Tools

 E-mail
 Print
 Discuss
 Blog

Related Products

Check out the products mentioned in this article: