下面就是在Internet Exploerer里直接调用这两个Web Method所得到的XML格式的结果:
表5. GetPersons()的返回结果
<?xml version="1.0" encoding="utf-8"?
<ArrayOfPerson xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://tempuri.org/"
<Person
<NameAlice</Name
<GenderFemale</Gender
</Person
<Person
<NameBob</Name
<GenderMale</Gender
</Person
<Person
<NameChris</Name
<GenderFemale</Gender
</Person
<Person
<NameDennis</Name
<GenderMale</Gender
</Person
</ArrayOfPerson
表6. GetPersonTable()的返回的String类型的值
<PersonTable <Person
<NameAlice</Name
<GenderFemale</Gender
</Person <Person
<NameBob</Name
<GenderMale</Gender
</Person <Person
<NameChris</Name
<GenderFemale</Gender
</Person <Person
<NameDennis</Name
<GenderMale</Gender
</Person <Person
<NameEric</Name
<GenderMale</Gender
</Person </PersonTable
到这里,XML Web Service的创建就已经完成了。.NET中创建的XML Web Services遵循的是统一的行业标准(SOAP、XML等),因此无论使用.NET语言还是使用非.NET语言,都可以调用它。尤其对于GetPersonTable()返回的结果来说,只要用XML Parser作简单的处理,就能把数据提取出来。下面就将演示如何在Java中完成这一处理。
3. 在Java中调用.NET Web Services,处理返回的数据集合
编写客户端调用Web Services时,最快速简便做法的是利用工具根据Web Services的WSDL描述生成客户端代理类(Proxy),而不是直接对SOAP Toolkit进行编程。在.NET Framework中,这个工作可以由wsdl.exe完成。在Java中,可以在JBuilder或者VisualAge Java等Java IDE中安装一个叫做WASP Developer的免费插件,这个插件也能完成由WSDL描述生成Proxy类的工作。另外,该公司还提供了WASP Server for Java和WASP UDDI,降低了用户用Java开发Web Services以及建立UDDI服务的难度。
在本文的例子中,用了JBuilder 7+WASP Developer来调用前文中建立的.NET XML Web Services。在调用之前,首先是用WASP Developer生成Proxy类。从图表7、8中可以看到,生成Proxy的工具已经在Java中也创建了一个Person类:
表7. 用WASP Developer生成的Proxy类
表8. WASP Developer创建的Person类
package javaclient.service1Soap12Clientstruct;
public class Person {
public java.lang.String Name;
public java.lang.String Gender;
}
/*
* Generated by WSDLCompiler, (c) 2002, Systinet Corp.
* http://www.systinet.com
*/
表9. 在Java中调用GetPersons()的代码
在Proxy类的基础上,就可以访问.NET编写的Web Services并提取数据了。对于GetPersons()来说,由于已经生成了Person类,所以调用代码非常简单直接:
import org.idoox.webservice.client.WebServiceLookup;
import org.idoox.wasp.Context;
import javax.swing.*;
import javax.swing.table.*;
try{
System.setProperty( "wasp.location","C:\\Home\\Util\\wasp_4.0SP2");
javaclient.service1Soap12Client.Service1Soap service;
String serviceURI = "http://localhost/dotNetHost/Service1.asmx";
String wsdlURI = "http://localhost/dotNetHost/Service1.asmx?wsdl";
WebServiceLookup lookup = (WebServiceLookup) Context.getInstance(Context.WEBSERVICE_LOOKUP);
service = (javaclient.service1Soap12Client.Service1Soap) lookup.lookup(
wsdlURI,
javaclient.service1Soap12Client.Service1Soap.class,
serviceURI);
Person[] persons=
service.GetPersons(new javaclient.service1Soap12Clientstruct.GetPersons()).GetPersonsResult;
DefaultTableModel model=new DefaultTableModel(new String[]{"name","gender"},0);
for(int i=0;i<persons.length;i++){
model.addRow(new String[]{persons[i].Name.toString(),persons[i].Gender.toString()});
}
this.jTable1.setModel(model);
}
catch(Exception ex)
{
javax.swing.JOptionPane.showMessageDialog(this,ex.getMessage());
}
调用GetPersonTable()并解析XML字符串要相对复杂一些,需要用到XML Parser从图表6中的XML字符串中提取数据,并逐一显示在JTable中。下面是从访问Web Method到解析XML,最后提取数据并显示的完整代码,及其运行结果截图:
import javax.swing.*;
import javax.swing.table.*;
import org.idoox.webservice.client.WebServiceLookup;
import org.idoox.wasp.Context;
import org.w3c.dom.*;
import org.apache.xml.serialize.*;
import org.apache.xerces.dom.*;
try{
System.setProperty( "wasp.location","C:\\Home\\Util\\wasp_4.0SP2");
javaclient.service1Soap12Client.Service1Soap service;
String serviceURI = "http://localhost/dotNetHost/Service1.asmx";
String wsdlURI = "http://localhost/dotNetHost/Service1.asmx?wsdl";
WebServiceLookup lookup = (WebServiceLookup) Context.getInstance(Context.WEBSERVICE_LOOKUP);
service = (javaclient.service1Soap12Client.Service1Soap) lookup.lookup(
wsdlURI,
javaclient.service1Soap12Client.Service1Soap.class,
serviceURI);
String result=
service.GetPersonTable(new javaclient.service1Soap12Clientstruct.GetPersonTable()).GetPersonTableResult;
DefaultTableModel model=new DefaultTableModel(new String[]{"name","gender"},0);
java.io.StringReader reader=new java.io.StringReader(result);
org.apache.xerces.parsers.DOMParser parser=new org.apache.xerces.parsers.DOMParser();
parser.parse(new org.xml.sax.InputSource(reader));
org.w3c.dom.Document document=parser.getDocument();
org.w3c.dom.NodeList children=document.getDocumentElement().getChildNodes();
for(int i=0;i<children.getLength();i++){
org.w3c.dom.Node node=children.item(i);
if(node.getNodeName().equals("Person")){
org.w3c.dom.NodeList personAttrNodes=node.getChildNodes();
String name="N/A";
String gender="N/A";
for(int j=0;j<personAttrNodes.getLength();j++){
org.w3c.dom.Node attrNode=personAttrNodes.item(j);
String attrNodeName=attrNode.getNodeName();
if(attrNodeName.equals("Name")){
name=attrNode.getFirstChild().getNodeValue();
}else if(attrNodeName.equals("Gender")){
gender=attrNode.getFirstChild().getNodeValue();
}else{
continue;
}
}
model.addRow(new String[]{name,gender});
}
}
this.jTable1.setModel(model);
}
catch(Exception ex)
{
javax.swing.JOptionPane.showMessageDialog(this,ex.getMessage());
}
4. 小结
从前面的叙述和代码中可以看出,对于"如何在Java/Delphi中使用.NET的Web Service返回的DataSet"的问题,虽然在非.NET语言环境中直接接受DataSet类型的返回值比较困难,但可以有其他的解决方案。
对于第一种解决方案,也就是采用自定义数据类型,它的优点是客户端代码非常简单,容易编写,而且容易理解。它的缺点是服务器端需要定义新的类,而且当通过ADO.NET从数据库中提取数据以后,还要再手工编写代码,将DataSet中的数据遍历一遍,转存成自定义类型的对象。
对于第二种解决方案,就是用DataSet.WriteXML()的方案,它的优点和缺点正好和第一种方案是互补的。它在客户端需要编写较多的代码,尤其是需要用XML Parser编程,提高了编程的难度。另一方面,它在服务器端比较简单。如果开发者在原先的纯.NET环境(即客户端也是.NET)中已经开发了返回类型为DataSet的Web Services,那么当开发者希望在客户端引入非.NET语言时,服务器端只需要简单的再增加一个Web Method,通过简单的WriteXML()调用对