cxf调用.net webservice之any元素
程序员文章站
2024-01-02 15:56:40
...
这两天工作之余帮前公司的小弟调一个比较恶心的Web Service问题。是CXF Java客户端调用.net Web Service的接口。接口返回类型是复杂类型,而且是<any> type,这个类型比较变态,cxf的wsdl2java不能很好的转换该类型。请看详请。
接口Wsdl主要内容展示:
关于<any>类型
<any> 元素
<any> 元素使我们有能力通过未被 schema 规定的元素来拓展 XML 文档!
下面这个例子是从名为 "family.xsd" 的 XML schema 中引用的片段。它展示了一个针对 "person" 元素的声明。通过使用 <any> 元素,我们可以通过任何元素(在
请看这个 schema 文件,名为 "children.xsd":
下面这个 XML 文件(名为 "Myfamily.xml"),使用了来自两个不同的 schema 中的成分,"family.xsd" 和 "children.xsd":
上面这个 XML 文件是有效的,这是由于 schema "family.xsd" 允许我们通过在 "lastname" 元素后的可选元素来扩展 "person" 元素。
<any> 和 <anyAttribute> 均可用于制作可扩展的文档!它们使文档有能力包含未在主 XML schema 中声明过的附加元素。
以上是网上介绍any的一个例子,一句话总结就是any可以是任意的复杂类型。并且是扩展的方法,不固定。
生成Java client stub
简要说明:
-p:生成类的包路径
-d:生成的类放在哪
-all:生成所有东西
生成的接收文件片断,可以看到any类型转换成List<Object>.
错误的调用代码:
}
下面是.net应该返回的any格式
<agent account='abc' name='aa' ....
List里面应该有对象Agent对象才对,但是没有,agent为null.
也就是说wsdl2java无法正常转换any type类型到java相关对象。
正确的调用方法:
用xerces-2.6.2.jar包解析any返回内容
这个里面result.getContent()里面的agent依旧为null,只好直接用org.apache.xerces.dom.ElementNSImpl接收相应any转换的元素,然后解析。
成功,结果如下:
总结
Cxf不能很好的处理.net web service中的any 元素,只好借助变态的解析方法。.net应该返回标准元素,如string等,这样的web service各语言调用起来才方便。Java也可以接收xml string后再解析。
相信此文能给那些想从cxf java客户端调用.net web service any元素的人带来方便。我在遇到此问题时,google了国内外的网站,没有提到cxf调用any类型的办法,所以总结写下此文,给后来者提供方便。
如果大家以前用cxf处理过.net any类型,有更好的办法,也希望能说说。
接口Wsdl主要内容展示:
<?xml version="1.0" encoding="utf-8" ?> - <wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:tns="http://esf.soufun.com/" xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" targetNamespace="http://esf.soufun.com/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"> - <wsdl:types> - <s:schema elementFormDefault="qualified" targetNamespace="http://esf.soufun.com/"> //.net接口 <s:element name="AgentInfo"> - <s:complexType> - <s:sequence> <s:element minOccurs="0" maxOccurs="1" name="userName" type="s:string" /> <s:element minOccurs="0" maxOccurs="1" name="pwd" type="s:string" /> </s:sequence> </s:complexType> </s:element> - //.net 接口返回类型。 <s:element name="AgentInfoResponse"> - <s:complexType> - <s:sequence> - <s:element minOccurs="0" maxOccurs="1" name="AgentInfoResult"> - <s:complexType mixed="true"> - <s:sequence> <s:any /> </s:sequence> </s:complexType> </s:element> </s:sequence> </s:complexType> </s:element> - //省略N多字 <wsdl:service name="Service"> - <wsdl:port name="ServiceSoap" binding="tns:ServiceSoap"> <soap:address location="http://agentinterfacen.test.soufun.com/HouseImportService/Service.asmx" /> </wsdl:port> - <wsdl:port name="ServiceSoap12" binding="tns:ServiceSoap12"> <soap12:address location="http://agentinterfacen.test.soufun.com/HouseImportService/Service.asmx" /> </wsdl:port> </wsdl:service> </wsdl:definitions>
关于<any>类型
<any> 元素
<any> 元素使我们有能力通过未被 schema 规定的元素来拓展 XML 文档!
下面这个例子是从名为 "family.xsd" 的 XML schema 中引用的片段。它展示了一个针对 "person" 元素的声明。通过使用 <any> 元素,我们可以通过任何元素(在
<lastname> 之后)扩展 "person" 的内容: <xs:element name="person"> <xs:complexType> <xs:sequence> <xs:element name="firstname" type="xs:string"/> <xs:element name="lastname" type="xs:string"/> <xs:any minOccurs="0"/> </xs:sequence> </xs:complexType> </xs:element>现在,我们希望使用 "children" 元素来扩展 "person" 元素。这此种情况下我们就可以这么做,即使以上这个 schema 的作者没有声明任何 "children" 元素。
请看这个 schema 文件,名为 "children.xsd":
<?xml version="1.0" encoding="ISO-8859-1"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.devwb.com" xmlns="http://www.devwb.com" elementFormDefault="qualified"> <xs:element name="children"> <xs:complexType> <xs:sequence> <xs:element name="childname" type="xs:string" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>
下面这个 XML 文件(名为 "Myfamily.xml"),使用了来自两个不同的 schema 中的成分,"family.xsd" 和 "children.xsd":
<?xml version="1.0" encoding="ISO-8859-1"?> <persons xmlns="http://www.microsoft.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:SchemaLocation="http://www.microsoft.com family.xsd http://www.devwb.com children.xsd"> <person> <firstname>David</firstname> <lastname>Smith</lastname> <children> <childname>mike</childname> </children> </person> <person> <firstname>Tony</firstname> <lastname>Smith</lastname> </person> </persons>
上面这个 XML 文件是有效的,这是由于 schema "family.xsd" 允许我们通过在 "lastname" 元素后的可选元素来扩展 "person" 元素。
<any> 和 <anyAttribute> 均可用于制作可扩展的文档!它们使文档有能力包含未在主 XML schema 中声明过的附加元素。
以上是网上介绍any的一个例子,一句话总结就是any可以是任意的复杂类型。并且是扩展的方法,不固定。
生成Java client stub
wsdl2java -p com.soufun.esf -d src -all http://agentinterfacen.test.soufun.com/HouseImportService/Service.asmx?wsdl
简要说明:
-p:生成类的包路径
-d:生成的类放在哪
-all:生成所有东西
生成的接收文件片断,可以看到any类型转换成List<Object>.
@XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = { "content" }) public static class AgentInfoResult { @XmlMixed @XmlAnyElement(lax = true) protected List<Object> content;
错误的调用代码:
public static void test() throws MalformedURLException { URL wsdlURL = new URL( "http://agentinterfacen.test.soufun.com/HouseImportService/Service.asmx?wsdl"); Service ss = new Service(wsdlURL, SERVICE_NAME); ServiceSoap port = ss.getServiceSoap12(); AgentInfoResult resp = port.agentInfo("ljxxx", "ljxxxx"); System.out.println("agentInfo.result=" + resp.getContent());
}
下面是.net应该返回的any格式
<agent account='abc' name='aa' ....
List里面应该有对象Agent对象才对,但是没有,agent为null.
也就是说wsdl2java无法正常转换any type类型到java相关对象。
正确的调用方法:
用xerces-2.6.2.jar包解析any返回内容
/** * 获取.net webservice any类型的数据。 */ public static void test2() { JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(); factory.getInInterceptors().add(new LoggingInInterceptor()); factory.getOutInterceptors().add(new LoggingOutInterceptor()); factory.setServiceClass(ServiceSoap.class); factory.setAddress("http://agentinterfacen.test.soufun.com/HouseImportService/Service.asmx?wsdl"); ServiceSoap service = (ServiceSoap) factory.create(); com.soufun.esf.AgentInfoResponse.AgentInfoResult result = service .agentInfo("ljxxx", "ljxxxx"); // javax.xml.soap.SOAPElement e=(SOAPElement) // result.getContent().get(0); for (int i = 0; i < result.getContent().size(); i++) { org.apache.xerces.dom.ElementNSImpl element = (ElementNSImpl) result .getContent().get(i); System.out.println(element.getAttributes().getNamedItem("account")); System.out.println(element.getAttributes().getNamedItem("name") .getNodeValue()); System.out.println(element.getAttributes().getNamedItem("level")); System.out.println(element.getAttributes().getNamedItem("score")); System.out.println(element.getAttributes().getNamedItem("mobile")); System.out.println(element.getAttributes().getNamedItem("email")); System.out.println(element.getAttributes().getNamedItem("mobile")); System.out.println(element.getAttributes().getNamedItem( "expiredDate")); } }
这个里面result.getContent()里面的agent依旧为null,只好直接用org.apache.xerces.dom.ElementNSImpl接收相应any转换的元素,然后解析。
成功,结果如下:
信息: Outbound Message --------------------------- ID: 1 Address: http://agentinterfacen.test.soufun.com/HouseImportService/Service.asmx?wsdl Encoding: UTF-8 Content-Type: text/xml Headers: {SOAPAction=["http://esf.soufun.com/AgentInfo"], Accept=[*/*]} Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><AgentInfo xmlns="http://esf.soufun.com/"><userName>ljcs2</userName><pwd>lj123456</pwd></AgentInfo></soap:Body></soap:Envelope> -------------------------------------- 2011-4-13 0:33:18 org.apache.cxf.interceptor.LoggingInInterceptor logging 信息: Inbound Message ---------------------------- ID: 1 Encoding: UTF-8 Content-Type: text/xml; charset=utf-8 Headers: {content-type=[text/xml; charset=utf-8], X-AspNet-Version=[2.0.50727], connection=[keep-alive], Vary=[Accept-Encoding], Date=[Tue, 12 Apr 2011 16:34:04 GMT], Content-Length=[716], X-UA-Compatible=[IE=EmulateIE7], X-Powered-By=[ASP.NET], Server=[nginx], Cache-Control=[private, max-age=0]} Payload: <?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><AgentInfoResponse xmlns="http://esf.soufun.com/"><AgentInfoResult><agent account="ljcs2" name="杜佳霖" level="三级" score="2500" mobile="01059107070" email="zhangguoqi@soufun.com" right="" expiredDate="2011-3-24 0:00:00" xmlns=""><branch name="链家导入测试" phone="" /><post all="10" store="0" uesd="0" /><tags><tag name="十万火急" remain="0" uesd="0" /><tag name="新推房源" remain="0" uesd="0" /></tags></agent></AgentInfoResult></AgentInfoResponse></soap:Body></soap:Envelope> -------------------------------------- account="ljcs2" 杜XX level="三级" score="2500" mobile="01059107070" email="zhangguoqi@soufun.com" mobile="01059107070" expiredDate="2011-3-24 0:00:00"
总结
Cxf不能很好的处理.net web service中的any 元素,只好借助变态的解析方法。.net应该返回标准元素,如string等,这样的web service各语言调用起来才方便。Java也可以接收xml string后再解析。
相信此文能给那些想从cxf java客户端调用.net web service any元素的人带来方便。我在遇到此问题时,google了国内外的网站,没有提到cxf调用any类型的办法,所以总结写下此文,给后来者提供方便。
如果大家以前用cxf处理过.net any类型,有更好的办法,也希望能说说。