跳到导航
BEA Dev2Dev Oracle and BEA
首页 资源中心 dev2dev学堂 在线技术论坛 User Group CodeShare
dev2dev 首页 > 资源中心 > 技术文章
在Web服务客户机和用户界面中使用XMLBean

时间:2004-11-27
作者:Steve Hanson
浏览次数:
本文关键字:soa
文章工具
推荐给朋友 推荐给朋友
打印文章 打印文章

该项技术的价值主张

    Web服务可以利用XML的能力在各不相同的应用程序中传送复杂数据。但是,如果您的Web服务客户端无法理解XML文档,那么就无法利用Web服务的这个主要优势。输入XMLBean,因为XMLBean是大小写敏感的,您就可以得到由Web服务提供的大量XML信息。

下载作者提供的与本文相关的文件。
  

本文可以分为两个部分。首先我会概述XMLBean的内容,解释XMLBean的概念,如何创建XMLBean以及如何在Web服务客户端与其他应用程序中使用它们。然后,我将在实例中使用XMLBean,通过Google的Web服务客户端来展现XMLBean的能力。

第 1 部分:XMLBean
什么是XMLBean?
  XMLBean本质上是一种处理XML文档的Java类型。但是XMLBean与传统的DOM和基于指针的API有所不同,因为它具备很强的类型感知能力。使用传统的API解析器,您在识别XML文档时或多或少是带有盲目性的,无法了解特定XML文档的丰富结构。传统的解析器只能识别XML中的父节点、子节点和兄弟节点,但是对于更强的功能就束手无策了。例如,传统的解析器可以按下列方式提取数据。XML文档如下:

    创建以下XML文档:

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

    XMLBean是类型感知的,或者可以说是“强类型的”,因为他们是基于XML Schema的。一个XMLBean可以识别出其Schema中的数据类型和设定规则。

创建XMLBean
   XMLBean类编译自一个XML Schema文件(XSD文件)。通过编译,构造了XMLBean,它可以识别出包含于Schema中的数据类型和设定规则。经编译的XMLBean可以解析任何与其Schema相一致的XML文档。
   使用BEA的WebLogic Workshop 8.1创建XMLBean的方法是将Schema文件置于一个Schema项目中,并且编译此项目。结果可以得到一套XMLBean的Java类型,每种类型都有丰富的API。下列Schema文件,BookList.xsd,可以编译成三种XMLBean的Java类型:MyBooks、BookArray和Book,它们中的每一个都具备丰富的API,可以识别数据类型。
 
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>

    上述三种Java类型可以在XMLBean的类文件夹中看到:



在应用程序中使用XMLBean

    如果您已经将Schema编译进XMLBean的类中,那么您可以使用XMLBean类来创建并且/或者处理任何与Schema一致的XML文档。在以SOAP XML文档通信的Web服务应用程序中,这尤其是一个强有力的技巧。本节的剩余部分将展示(1)如何在Web服务中使用XMLBean类以及(2)如何在Web服务客户端中使用XMLBean类。整个过程中,我将使用下面的简单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>

    为了让您了解这个Schema是多么的简单,我将提供两个与此Schema相一致的XML文档:

<HelloMessage>
    Hello, World!
</HelloMessage>
 
<HelloMessage>
    Hello, Moon!
</HelloMessage>

    当HelloWorld.xsd被编译时,可以生成一个XMLBean类:helloWorldSchemaTypes.HelloMessage。



(1)在Web服务中使用XMLBean
   在Web服务中,XMLBean类主要用于创建新XML文档并且通过调用Web服务方法返回这些文档。使用XMLBean类创建新XML文档的基本过程如下。

1.编写一个Schema文件(.xsd文件),设置您的XML文档所要遵循的规则。下述文档描述完成此任务的一种方式:“How Do I: Generate Schema from an XML Instance Document?”
2.在Schema项目中保存Schema文件。
3.编译Schema项目。
4.将创建的XMLBean类导入Web服务中。

        import mySchema.MyXMLBeanClass;

5.通过调用XMLBean类中的方法创建并且操作新的XML文档。通过每个XMLBean类中的Factory.newInstance()方法创建新的实例文档。

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


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

 
6.使用Web服务的方法和/或回调,可以将XMLBean类型传给客户端。(相关XML文档将作为SOAP文档的有效负载来传递。)

下列Web服务使用XMLBean类的HelloMessageDocument来为每个客户请求创建XML文档。导入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;
    }
}

  如果客户端提供了参数“World!”,Web服务将创建下列XML文档。

    <HelloMessage>
        Hello, World!
    </HelloMessage>
 
  注意,Web服务方法可以将XMLBean类型返回给其客户端:HelloMessageDocument。当Web服务返回一个XMLBean类型时,原始的Schema(创建XMLBean的Schema) 自动在Web服务的WSDL文件中提供。这就允许Web服务的客户端在终端复制XMLBean类。这也将Web服务和它们的客户端在数据类型方面相一致。  

(2)在Web服务的客户端使用XMLBean

  在Web服务客户端中,XMLBean主要用来从SOAP XML文档中解析、操作并且提取数据,其中SOAP XML文档由Web服务返回。
  在Web服务的客户端解析并且提取SOAP XML文档中数据的基本过程如下:
1.获取由Web服务主机发出的SOAP XML消息的Schema文件(.XSD文件)。某些情况下,您可以仅仅将Web服务的WSDL文件看作是Schema文件(.XSD文件)。在这些情况下,您可以将WSDL保存于您的Schema项目中,并且直接从WSDL编译出XMLBean类。



    但是,在其他情况下,WSDL包含由WSDL特定类型的参考语法,您必须以其他方式获取Schema文件。WSDL特定语法的例子请见下面对数组类型的引用。  

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

1.如果您不能直接使用WSDL文件编译XMLBean类,那么下列文档示出了从实例XML文档中创建Schema文件的一种方式:“How Do I: Generate Schema from an XML Instance Document?”
2.在Schema项目中保存Schema(或者WSDL)文件。
3.编译Schema项目。
4.将XMLBean类导入Web服务客户端。

import mySchema.MyXMLBeanClass;

  假定从Web服务传来的SOAP XML消息与Schema文件相一致,您可以在它们从Web服务主机到达时将其解析成XMLBean。

      MyXMLBeanClass message = helloWorldControl.hello();

第 2 部分:通过 Google Web服务使用XMLBean  
  在继续本文之前,推荐您下载Google软件开发包并且获取Google Web API的许可之匙。Google为了使其搜索引擎应用的范围更广,提供了其搜索引擎的Web服务接入点。WSDL文件描述了此Web服务:http://api.google.com/GoogleSearch.wsdl. 通过上述Web服务,任何可以处理XML文档并且在Internet上通信的软件就可以成为Google Web服务的一个客户端。
  您构建的下述应用程序将会具有如下架构。Web服务控件将会使用Google Web服务处理SOAP流量。它也将这些SOAP文档解析为XMLBean形式,并且传递给应用程序的用户界面,为呈现给用户做进一步处理。


使用Google Web的示例SOAP请求/响应

  下面提供Web服务控件和Google Web服务之间的一个示例SOAP请求/响应交换。一个请求至少需要包含两个参数:查询条件和开发商许可证。在下列请求中,查询条件为:“Plato”,返回结果的最大值被限于2。

  调用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>

  得到下述SOAP响应:
  上述请求创建了下面的响应文档。正如您所看到的,在响应文档中的XML是相当复杂的,我们正好可以使用XMLBean来处理它。但是,您如何才能获取能够识别响应文档内部数据类型的Schema呢?下面的步骤指导将演示如何获得Schema以及如何解析响应文档。

<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>


一步一步的指导
第1步:设置
  在WebLogic Workshop中,选择File-->New-->Application。
  在New Application对话框的右边窗格中,选择Default Application。根据您的喜好完成其余对话框的选择。

第2步:为Google搜索结果创建Schema和XMLBean类型
  在许多情况下,可以通过编译Web服务中的WSDL来捕获Web服务中数据类型的XMLBean版本:但是Google的WSDL不属于上述情况。
  您不能从Google的WSDL中直接编译XMLBean类,因为您使用特定于SOAP的语法来描述数组类型(XMLBean目前仅仅支持Schema类型):

      <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>

  由于这个原因,您必须为Google Web服务创建XML Schema,以此来捕获服务返回的数据类型。通过检查服务返回的SOAP消息并且编辑相应的原始WSDL文件,可以得到目标XML Schema文件。

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>

  在Schema项目中保存Schema文件GoogleSearch.xsd并对其进行编译,则生成下述五个XMLBean类:



第3步:从WSDL文件中创建Web服务控件
   在这一步中,您将自动从Web服务的WSDL文件中生成Web服务控制文件。Web服务控件处理客户端与Google Web服务之间的SOAP流量。它可以向Web服务发送SOAP消息请求,监听SOAP响应并且将它们转发至界面。在这一步中,我们在将SOAP响应响应转发至用户界面之前,先构建把SOAP消息转换成XMLBean类型的Web服务。
  在您的Web应用程序项目中保存WSDL文件(位于http://api.google.com/GoogleSearch.wsdl)。
  右击WSDL文件并选择Generate Service Control。

在Generate using XmlBean对话框中,选择Yes。



  Web服务控制文件GoogleSearchControl.jcx被创建。选择Yes,就可以使用Web服务控件的方法来返回XMLBean类型。例如,下述GoogleSearchControl.jcx的方法可以返回XMLBean类型(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);

第4步:创建用户界面
  现在可以查询Google搜索引擎并获取XMLBean形式的响应。最后一步就是创建用户界面,以有用且直观的方式解析并且显示这些结果。不论您的用户界面如何,由于搜索结果是XMLBean形式的,您拥有丰富的API来提取响应的数据。
  例如,您可以使用下列代码打印出所有的<title> 元素:

        // 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() );
        }

JSP页面的XMLBean数据绑定
  您也可以在JSP页面中使用XMLBean。使用WebLogic Workshop的“数据绑定”技术,您可以在JSP页面中调用Java类型,而不在JSP页面上放置Java代码。这一点很大程度上实现了Web应用程序中的代码与界面的分离。但是,由于JSP页面以类型感知的方式调用Java数据,所以JSP页面中仍然保留类型感知能力,这会为您提供很大方便。
例如,假设您在页面流文件(带有JPF扩展的Java文件)中使用下面的XMLBean数据。
  googleSearch.GoogleSearchResult results = myControl.doGoogleSearch(...supply parameters here...);
  您可以使用WebLogic Workshop的一种特殊的具有数据绑定功能的标签来绑定JSP页面和Java数据。(这些标签以前缀“netui”开始)。

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

  需要注意的是,这个JSP标签不包括Java代码(使用的表达语言是ECMA脚本),但是它在表达式“pageFlow.results.resultElements.itemArray[0].URL”中保持了Java的类型感知能力。

 作者简介
 
dot dot dot

dot
  作者其它文章
您对本文的评价
您对这篇文章的看法如何?
太棒了!5分 不错啊 4分 一般般 3分 有待提高 2分 不好 1分