请将下面的代码完整复制到soapclient.js中
/**//***************************************************************************** AJAX Javascript "SOAP Client" library Thank to Mr.Matteo Casati, Ihar Voitka - http://www.guru4.net/ Author: ZhangLiang, E-Mail:cheungmine@gmail.com Date: 2006-8-31*****************************************************************************/function _debug(rownum, msg) ...{ alert(rownum+":"+msg); }var SOAP_SUCCESS = 0;var SOAP_FAULT = 1;var _sr_env_hdr_ = "<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" " + "xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">"; var _sr_body_hdr_ = "<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">";var _soap_header_m_token_ = ""; // global varible, soap_header: m_tokenfunction SOAPParams(callid, url, method, async, callback, username, password)...{ this.callid = callid; this.url = url; // "http://localhost/MtkWebgisServer/MtkWebgis.dll?Handler=GenMtkWebgisWSDL"; this.svc = null; //"http://cl2/MtkWebgisServer/MtkWebgis.dll?Handler=Default"; // 未完 this.method = method; if (async+"" == "undefined") this.async = true; // default value else this.async = async; if (this.async)...{ if (callback+"" == "undefined") this.callback = soap_callback; else this.callback = callback; } this.username = null; if (username+"" != "") this.username = username; this.password = null; if (password+"" != "") this.password = password; this.wsdl = null; this.result = SOAP_FAULT; this.xmlhttp = null; // xmlhttp object returned this._pl = new Array(); // input parameters list this.add = function(name, value)...{ this._pl[name] = value; return this; } this.toXml = function()...{ var xml = ""; for(var p in this._pl)...{ var t = typeof(this._pl[p]); if (t == "object" || t == "function") xml += "<" + p + ">" + this._pl[p].toXml() + "</" + p + ">"; else xml += "<" + p + ">" + this._pl[p].toString().replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">") + "</" + p + ">"; } return xml; } this.setToken = function()...{ if (this.method=="login")...{ _soap_header_m_token_ = this.getval("snp:m_token"); } } this.getToken = function()...{ return _soap_header_m_token_; } this.getval = function(name)...{ var ret = SOAPClient._getElementsByTagName(this.xmlhttp.responseXML.documentElement, name).item(0); return ret.text; } this.retval = function()...{ return this.getval("return"); } // SOAP:Fault this.faultcode = function()...{ return this.getval("faultcode"); } this.faultstring = function()...{ return this.getval("faultstring"); } this.faultdetail = function()...{ return this.getval("detail"); }}function SOAPClient()...{}SOAPClient.invoke = function(params)...{ params.result = SOAP_FAULT; if(params.async) SOAPClient._loadWsdl(params); else return SOAPClient._loadWsdl(params);}// private: wsdl cacheSOAPClient_cacheWsdl = new Array();// private: invoke asyncSOAPClient._loadWsdl = function(params)...{ // load from cache? params.wsdl = SOAPClient_cacheWsdl[params.url]; if(params.wsdl + "" != "" && params.wsdl + "" != "undefined")...{ params.svc = SOAPClient._getService(params.wsdl); return SOAPClient._sendSoapRequest(params); } // get wsdl var _xmlhttp = SOAPClient._getXmlHttp(); if (params.username+"" != "undefined") _xmlhttp.open("GET", params.url, params.async, params.username, params.password); else _xmlhttp.open("GET", params.url, params.async); if(params.async)...{ _xmlhttp.onreadystatechange = function()...{ if(_xmlhttp.readyState == 4) SOAPClient._onLoadWsdl(params, _xmlhttp); } } _xmlhttp.send(null); if (!params.async) return SOAPClient._onLoadWsdl(params, _xmlhttp);}SOAPClient._onLoadWsdl = function(params, req)...{ if (req.readyState == 4 && req.status == 200)...{ params.wsdl = req.responseXML; params.svc = SOAPClient._getService(params.wsdl); SOAPClient_cacheWsdl[params.url] = params.wsdl; // save a copy in cache return SOAPClient._sendSoapRequest(params); } return SOAP_FAULT;}SOAPClient._sendSoapRequest = function(params)...{ // get namespace, ok var ns = SOAPClient._getAttribValue(params.wsdl.documentElement, "targetNamespace"); // 构造SOAP请求, SOAP 2.0 var sr = _sr_env_hdr_ + "<soap:Header><snp:m_token xmlns:snp=""+ns+"">" + _soap_header_m_token_ + "</snp:m_token></soap:Header>" + _sr_body_hdr_ + "<snp:" + params.method + " xmlns:snp="" + ns + "">" + params.toXml() + "</snp:" + params.method + "></soap:Body></soap:Envelope>"; // send request params.xmlhttp = SOAPClient._getXmlHttp(); params.xmlhttp.open("POST", params.svc, params.async); params.xmlhttp.setRequestHeader("SOAPAction", ""#"+params.method+"""); // SOAPAction: "#HelloWorld" params.xmlhttp.setRequestHeader("Content-Type", "text/xml; charset=utf-8"); if(params.async)...{ params.xmlhttp.onreadystatechange = function()...{ if(params.xmlhttp.readyState == 4) SOAPClient._onSendSoapRequest(params); } } try...{ params.xmlhttp.send(sr); } catch(ex)...{} if (!params.async) return SOAPClient._onSendSoapRequest(params);}SOAPClient._onSendSoapRequest = function(params)...{ if (params.xmlhttp.readyState == 4 && params.xmlhttp.status == 200)...{ params.result = SOAP_SUCCESS; // 未完... params.setToken(); // 设置全局变量: _soap_header_m_token_ } if(params.async && params.callback) params.callback(params.result, params); if (!params.async) return params.result;}// private: utilsSOAPClient._getElementsByTagName = function(document, tagName, ns)...{ try...{ // trying to get node omitting any namespaces (latest versions of MSXML.XMLDocument) var lst = document.selectNodes(".//*[local-name()=""+ tagName +""]"); if (lst.length == 0) throw 0; return lst; } catch (ex)...{} // old XML parser support if (ns+"" == "undefined") return document.getElementsByTagName(tagName); return document.getElementsByTagName(ns+":"+tagName); }SOAPClient._getService = function(wsdl)...{ var soap_address = SOAPClient._getElementsByTagName(wsdl.documentElement, "address", "soap").item(0); return SOAPClient._getAttribValue(soap_address, "location");}SOAPClient._getAttribValue = function(node, name)...{ return (node.attributes[name]+"" == "undefined") ? node.attributes.getNamedItem(name).nodeValue : node.attributes[name].value;}// private: xmlhttp factorySOAPClient._getXmlHttp = function() ...{ try...{ if(window.XMLHttpRequest)...{ var req = new XMLHttpRequest(); // some versions of Moz do not support the readyState property and the onreadystate event so we patch it! if(req.readyState == null) ...{ req.readyState = 1; req.addEventListener("load", function() ...{ req.readyState = 4; if(typeof req.onreadystatechange == "function") req.onreadystatechange(); }, false); } return req; } else if(window.ActiveXObject) ...{ return new ActiveXObject(SOAPClient._getXmlHttpProgID()); } } catch (ex) ...{} throw new Error("Your browser does not support XmlHttp objects");}SOAPClient._getXmlHttpProgID = function()...{ if(SOAPClient._getXmlHttpProgID.progid) return SOAPClient._getXmlHttpProgID.progid; var progids = ["Msxml2.XMLHTTP.5.0", "Msxml2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"]; var o; for(var i = 0; i < progids.length; i++) ...{ try ...{ o = new ActiveXObject(progids[i]); return SOAPClient._getXmlHttpProgID.progid = progids[i]; } catch (ex) ...{}; } throw new Error("Could not find an installed XML parser");}假设ATL XML WebServices实现方法如下:
[id(1), helpstring("登入系统, 获得用户令牌和全图URL, 以后任何方法调用必须给出令牌")]HRESULT login([in] BSTR Username, [in] BSTR Password);id(2), helpstring("刷新地图, 取地图imgURL")]HRESULT refresh([out] DOUBLE* Scale, [out, retval] BSTR *imgURL);客户端IE中调用如下:
<HTML> <HEAD> <TITLE>WebGis Demo Page - WebGis AJAX Client</TITLE> <script language="javascript" src="ajax/soapclient.js"></script> <script language="javascript"> // WebService URL var g_url = "http://cl2/mtkwebgis/MtkWebgis.dll?Handler=GenMtkWebgisWSDL"; function soap_callback(rcode, params) ...{ if (rcode == SOAP_SUCCESS) ...{ switch (params.callid) ...{ case "刷新": imgMap.src = params.retval(); // retval() 取得[out,retval]参数 alert( "当前比例:" + params.getval("Scale") ); // getval(...) 取得[out]参数break;
} } else ...{ alert(params.callid+":发生错误"); } } function Login() ...{ // 同步调用, 获得令牌 var soap = new SOAPParams("登录", g_url, "login", false); soap.add("Username", "cheung"); soap.add("Password", "mine"); if (SOAP_SUCCESS == SOAPClient.invoke(soap)) refresh(); else alert("登录失败"); } function Refresh() ...{ // 异步调用刷新, 默认回调函数soap_callback var soap = new SOAPParams("刷新", g_url, "refresh"); SOAPClient.invoke(soap); } </script> </HEAD> <BODY onload="Login();"> <div id="divMap"><img id="imgMap"></div> </BODY></HTML>使用soapclient.js需要注意,我假设XML WebServices必须存在如上面所示的login方法,用于验证用户,而且m_token必须是soap头。login原型如下:
[ soap_method ][ soap_header( value = "m_token", out = true ) ]HRESULT login(/**//*[in]*/ BSTR Username, /**//*[in]*/ BSTR Password)...{ CHAR szID[MAX_TOKEN_LEN + 1]; *szID = 0; DWORD dwSize = MAX_TOKEN_LEN; HRESULT hr = m_spSessionSvc->CreateNewSession(szID, &dwSize, &m_spSession); CHECK_FAILED(hr); szID[dwSize] = 0; m_token = CComBSTR(szID).Detach(); return hr;}这样,用户就可以通过soapclient.js在IE中直接调用ATL Server写的XML WebServices了。
(本文写于2006年9月,cheungmine,上海新区时空信息技术有限公司)