|
I had a similar issue. The problem wasn't that the method didn't have a namespace, it's that the children underneath the method (the parameters) ALSO used the same namespace, which messed things up.
My fix to that line of code was:
var sr =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<soapenv:Envelope " +
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
"xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" " +
"xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
"<soapenv:Body>" +
"<ns1:" + method + " xmlns:ns1=\"" + ns + "\">" +
parameters.toXml() +
"</ns1:" + method + "></soap:Body></soap:Envelope>";
This makes it so the parameters don't use that namespace (ns1).
Daniel Tingstrom
|
|
|
|
|
I´ve changed some methods to make this more like a stub: it add´s the WSDL functions to the SOAPClient class. This means that we don´t have to get the correct url, methodname and type. I´ve used your code as a bases and made some new methods. It´s tested with your WSDL, Axis 1 WSDL and a gSOAP WSDL and they parsed.
Sorry VB.Net it took a little while to response, as you can see i´ve been busy.
The functions are added in a the following fashion: ws<WebserviceName><WebserviceMethod>(async, callback or null, params)
The constructor has been given to params: to parse or not to parse and the WSDL url.
Note: the stub only works on the global level, this means: NOT in a function. But i will look into this.
NEW code, I should have made clear that ie wasn´t working,
This is a test sample use Matteo's webservice:
<script>
var soapi = new SOAPClient("http://www.guru4.net/articoli/javascript-soap-client/demo/webservicedemo.asmx?wsdl", true);
function test() {
SOAPClient.wsWebServiceDemoSoapHelloTo(true, called, "Marco");
}
function called(back) {
alert(back);
}
</script>
<BUTTON onclick="test()" >TEST</BUTTON>
Have fun,
Marco.
/*****************************************************************************\
Javascript "SOAP Client" library
@version: 2.0 BETA 1 - 2006.03.12
@author: Matteo Casati - http://www.guru4.net/
@description: added support for complex object as webservice input paramaters
@version: 1.5 - 2006.02.20
@author: Matteo Casati, Martin Reich - http://www.guru4.net/
@description: the SOAPClient._onSendSoapRequest method has been updated
to handling SOAP exceptions in async calls
@version: 1.4 - 2005.12.10
@author: Matteo Casati, Ihar Voitka - http://www.guru4.net/
@description: (1) SOAPClientParameters.add() method returns 'this' pointer.
(2) "_getElementsByTagName" method added for xpath queries.
(3) "_getXmlHttpPrefix" refactored to "_getXmlHttpProgID" (full
ActiveX ProgID).
@version: 1.3 - 2005.12.06
@author: Matteo Casati - http://www.guru4.net/
@description: callback function now receives (as second - optional - parameter)
the SOAP response too. Thanks to Ihar Voitka.
@version: 1.2 - 2005.12.02
@author: Matteo Casati - http://www.guru4.net/
@description: (1) fixed update in v. 1.1 for no string params.
(2) the "_loadWsdl" method has been updated to fix a bug when
the wsdl is cached and the call is sync. Thanks to Linh Hoang.
@version: 1.1 - 2005.11.11
@author: Matteo Casati - http://www.guru4.net/
@description: the SOAPClientParameters.toXML method has been updated to allow
special characters ("<", ">" and "&"). Thanks to Linh Hoang.
@version: 1.0 - 2005.09.08
@author: Matteo Casati - http://www.guru4.net/
@notes: first release.
\*****************************************************************************/
//private
var _wsdl_url = null;
function SOAPClientParameters()
{
var _pl = new Array();
this.add = function(name, value)
{
_pl[name] = value;
return this;
}
this.toXml = function()
{
var xml = "";
for(var p in _pl)
xml += "<" + p + ">" + SOAPClientParameters._serialize(_pl[p]) + "</" + p + ">";
return xml;
}
}
SOAPClientParameters._serialize = function(o)
{
var s = "";
switch(typeof(o))
{
case "string":
s += o.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">"); break;
case "number":
case "boolean":
s += o.toString(); break;
case "object":
// Date
if(o.constructor.toString().indexOf("function Date()") > -1)
{
var year = o.getFullYear().toString();
var month = (o.getMonth() + 1).toString(); month = (month.length == 1) ? "0" + month : month;
var date = o.getDate().toString(); date = (date.length == 1) ? "0" + date : date;
var hours = o.getHours().toString(); hours = (hours.length == 1) ? "0" + hours : hours;
var minutes = o.getMinutes().toString(); minutes = (minutes.length == 1) ? "0" + minutes : minutes;
var seconds = o.getSeconds().toString(); seconds = (seconds.length == 1) ? "0" + seconds : seconds;
var milliseconds = o.getMilliseconds().toString();
var tzminutes = Math.abs(o.getTimezoneOffset());
var tzhours = 0;
while(tzminutes >= 60)
{
tzhours++;
tzminutes -= 60;
}
tzminutes = (tzminutes.toString().length == 1) ? "0" + tzminutes.toString() : tzminutes.toString();
tzhours = (tzhours.toString().length == 1) ? "0" + tzhours.toString() : tzhours.toString();
var timezone = ((o.getTimezoneOffset() < 0) ? "+" : "-") + tzhours + ":" + tzminutes;
s += year + "-" + month + "-" + date + "T" + hours + ":" + minutes + ":" + seconds + "." + milliseconds + timezone;
}
// Array
else if(o.constructor.toString().indexOf("function Array()") > -1)
{
for(var p in o)
{
if(!isNaN(p)) // linear array
{
(/function\s+(\w*)\s*\(/ig).exec(o[p].constructor.toString());
var type = RegExp.$1;
switch(type)
{
case "":
type = typeof(o[p]);
case "String":
type = "string"; break;
case "Number":
type = "int"; break;
case "Boolean":
type = "bool"; break;
case "Date":
type = "DateTime"; break;
}
s += "<" + type + ">" + SOAPClientParameters._serialize(o[p]) + "</" + type + ">"
}
else // associative array
s += "<" + p + ">" + SOAPClientParameters._serialize(o[p]) + "</" + p + ">"
}
}
// Object or custom function
else
for(var p in o)
s += "<" + p + ">" + SOAPClientParameters._serialize(o[p]) + "</" + p + ">";
break;
default:
throw new Error(500, "SOAPClientParameters: type '" + typeof(o) + "' is not supported");
}
return s;
}
/*
class to store method information
*/
function SOAPClientMethod(aName, aUrl, ns) {
this.name = aName;
this.url = aUrl;
this.namespace = ns;
this.paramsIn = {};
this.paramsOut = {};
this.method = "";
}
var global = this;
var soapClientMethods = {};
function SOAPClient(wsdl_url, createMethods)
{
_wsdl_url = wsdl_url;
this.methods = {};
if (_wsdl_url)
{
var xmlHttp = SOAPClient._getXmlHttp();
xmlHttp.open("GET", _wsdl_url, true);
xmlHttp.onreadystatechange = function()
{
if(xmlHttp.readyState == 4)
{
var uddi = xmlHttp.responseXML;
if (uddi)
{
var name = null;
var definition = SOAPClient._getElementsByTagName(uddi, "definitions")[0];
var namespace = definition.getAttribute("targetNamespace");
var services = SOAPClient._getElementsByTagName(uddi, "service");
for (var service = 0; service < services.length; service++)
{
var ports = SOAPClient._getElementsByTagName(services[service], "port");
for (var port = 0; port < ports.length; port++)
{
name = ports[port].getAttribute("name");
var addresses = SOAPClient._getElementsByTagName(ports[port], "address");
var bName = ports[port].getAttribute("binding").split(':')[1];
var bindings = SOAPClient._getElementsByTagName(uddi, "binding");
for (var binding = 0; binding < bindings.length; binding++)
{
if (bName == bindings[binding].getAttribute("name"))
{
var ptName = bindings[binding].getAttribute("type").split(':')[1];
var url = null;
for(var address = 0; address < addresses.length; address++)
{
url = addresses[address].getAttribute("location");
if (url != null) SOAPClient_cacheWsdl[url] = uddi;
}
var portTypes = SOAPClient._getElementsByTagName(uddi, "portType");
for(var portType = 0; portType < portTypes.length; portType++)
{
var prName = portTypes[portType].getAttribute("name");
if(prName == ptName)
{
var operations = SOAPClient._getElementsByTagName(portTypes[portType], "operation");
var messages = SOAPClient._getElementsByTagName(uddi, "message");
var elements = SOAPClient._getElementsByTagName(uddi, "element");
var complexTypes = SOAPClient._getElementsByTagName(uddi, "complexType");
var types = SOAPClient._getElementsByTagName(uddi, "types")[0];
for (var operation = 0;operation < operations.length; operation++)
{
var methodname = operations[operation].getAttribute("name");
soapClientMethods["ws" + name + methodname] = new SOAPClientMethod("ws" + name + methodname, url, namespace);
soapClientMethods["ws" + name + methodname].method = methodname;
var inputs = SOAPClient._getElementsByTagName( operations[operation], "input");
SOAPClient._processInputs(inputs, messages, types, complexTypes, soapClientMethods["ws" + name + methodname].paramsIn);
var outputs = SOAPClient._getElementsByTagName(operations[operation], "output");
SOAPClient._processInputs(outputs, messages, types, complexTypes, soapClientMethods["ws" + name + methodname].paramsOut);
}
}
}
}
}
}
}
}
var tmp;
for (s in soapClientMethods)
{
var pList = "(async, callback, ";
var params = "var soapP = new SOAPClientParameters();";
for (p in soapClientMethods[s].paramsIn)
{
pList += p + ", ";
params += "soapP.add(\"" + p + "\", " + p + ");";
}
pList = pList.substring(0, pList.lastIndexOf(","));
pList += ")";
//url, method, parameters, async, callback, soapClientMethod
var scriptText = "global._" + s + " = function " + pList + " {" + params
+ " return SOAPClient._sendSoapRequest2(\"" + soapClientMethods[s].url + "\", \""
+ soapClientMethods[s].method+"\", soapP, async, callback, soapClientMethods[\"" + s +
"\"]);}";
(global.eval) ? global.eval(scriptText) : eval(scriptText);
(global.eval) ? global.eval(("SOAPClient." + s + " = _" + s)) : eval(("SOAPClient." + s + " = _" + s));
if (eval("typeof(\"SOAPClient.\" + s)")=="string")
{
scriptText = "function _"+ s + pList + " {" + params
+ " return SOAPClient._sendSoapRequest2(\"" + soapClientMethods[s].url + "\", \""
+ soapClientMethods[s].method+"\", soapP, async, callback, soapClientMethods[\"" + s +
"\"]);};";
(global.eval) ? global.eval(scriptText) : eval(scriptText);
(global.eval) ? global.eval(("SOAPClient." + s + " = _" + s)) : eval(("SOAPClient." + s + " = _" + s));
}
}
}
}
xmlHttp.send(null);
}
}
SOAPClient._processInputs = function (inputs, messages, types, complexTypes, params)
{
for (var input = 0; input < inputs.length; input++)
{
var mName = inputs[input].getAttribute("message").split(':')[1];
var parts = null;
for (var message = 0; message < messages.length && parts==null; message++)
{
if (mName == messages[message].getAttribute("name"))
{
parts = SOAPClient._getElementsByTagName(messages[message], "part");
for (var part = 0; part < parts.length; part++)
{
var pName = parts[part].getAttribute("name");
if (varType = parts[part].getAttribute("type"))
{
var tmp = null;
var varType = varType.split(':')[1];
tmp = SOAPClient._makeVariable(pName, varType, tmp, null, params);
params[pName] = tmp;
}
else
{
var inElmName = parts[part].getAttribute("element").split(':')[1];
var schema = SOAPClient._getElementsByTagName( types, "schema")[0];
var typeElements = SOAPClient._getElementsByTagName(schema, "element");
var stop = false;
for (var element = 0; element < typeElements.length && !stop; element++)
{
if (typeElements[element].getAttribute("name") == inElmName)
{
var scTypes = typeElements[element].childNodes; //simple or complextype, (n)ever seen any simple examples?
for (var scType=0; scType < scTypes.length && !stop; scType++)
{
if ((scTypes[scType].localName
&& (scTypes[scType].localName == "complexType" || scTypes[scType].localName == "simpleType"))
|| (scTypes[scType].nodeName &&
( scTypes[scType].nodeName.split(':')[1] == "complexType" || scTypes[scType].nodeName.split(':')[1] == "simpleType")))
{
SOAPClient._parseType(scTypes[scType], complexTypes, null, params);
stop = true; //break
}
}
}
}
}
}
}
}
}
}
SOAPClient._parseType = function(scType, complexTypes, o, params )
{
var tmp = null;
if (scType.hasChildNodes())
{
//TODO localName
var egcsa = null; //element, group, choice, sequence, any
var elements = scType.childNodes;
for (var element=0; element < elements.length && egcsa == null; element++)
{
var elName = (elements[element].localName) ? elements[element].localName : elements[element].nodeName.split(":")[1];
if (elName == "element"
|| elName == "sequence"
|| elName == "group"
|| elName == "choice"
|| elName == "any"
)
{
egcsa = elements[element].childNodes;
}
}
for (var elmEgcsa=0; elmEgcsa < egcsa.length; elmEgcsa++)
{
var egcsaName = (egcsa[elmEgcsa].localName) ? egcsa[elmEgcsa].localName : egcsa[elmEgcsa].nodeName.split(':')[1];
if (egcsaName == "element" )
{
var varName = egcsa[elmEgcsa].getAttribute("name");
var varType = egcsa[elmEgcsa].getAttribute("type").split(':')[1];
var varMinOcc = egcsa[elmEgcsa].getAttribute("minOccurs");
var varMaxOcc = egcsa[elmEgcsa].getAttribute("maxOccurs");
tmp = SOAPClient._makeVariable(varName, varType, tmp, o, complexTypes, params);
}
}
}
//tmp == null void soap call
if (o == null && tmp != null) params[varName] = tmp;
}
SOAPClient._makeVariable = function(varName, varType, tmp, o, complexTypes, params)
{
if (varType.toLowerCase().indexOf("arrayof") == 0) // starts width
{
var aType = varType.substring(7, varType.length);
if(aType.indexOf('_') >-1)
{
//Axis ArrayOf_xsd_bla bla and ArrayOf_soapenc_bla bla
//for native array?s
aType = aType.substring(aType.lastIndexOf('_') + 1, varType.length);
}
tmp = SOAPClient._getNativeForStringType(aType);
tmp.isAArray = true;
tmp.typeName = aType;
if (o == null && typeof(tmp) == "object")
{
//We need to determin the nature of the complextype
SOAPClient._findAndParseComplexType(complexTypes, tmp, aType, params);
}
else
{
if (o != null)
{
(global.eval) ? global.eval("o." + varName + " = tmp") : eval("o." + varName + " = tmp");
}
}
}
else
{
tmp = SOAPClient._getNativeForStringType(varType);
tmp.typeName = varType;
if (o == null && typeof(tmp) == "object")
{
tmp.isAArray = false;
//mind: it's recursive
SOAPClient._findAndParseComplexType(complexTypes, tmp, varType, params);
}
else
{
if (o != null)
{
(global.eval) ? global.eval("o." + varName + " = tmp") : eval("o." + varName + " = tmp");
}
}
}
return tmp;
}
SOAPClient._findAndParseComplexType = function (complexTypes, o, objectName, params)
{
for (var complexType = 0; complexType < complexTypes.length; complexType++)
{
if (objectName == complexTypes[complexType].getAttribute("name"))
{
//mind: it's recursive, to complex types could blow up the browser!
SOAPClient._parseType(complexTypes[complexType], complexTypes, o, params);
}
}
}
SOAPClient._getNativeForStringType = function (type)
{
var o = null;
switch (type)
{
case "string": o = new String("");break;
case "gYearMonth": o = new String("");break;
case "gYear": o = new String("");break;
case "gMonthDay": o = new String("");break;
case "gDay": o = new String("");break;
case "gMonth": o = new String("");break;
case "hexBinary": o = new String("");break;
case "anyURI": o = new String("");break;
case "QName": o = new String("");break;
case "NOTATION": o = new String("");break;
case "boolean": o = new Boolean(true);break;
case "decimal": o = new Number(0);break;
case "float": o = new Number(0.0);break;
case "double": o = new Number(0E00);break;
case "duration": o = new Number(0);break;
case "dateTime": o = new Date();break;
case "time": o = new Time();break;
case "date": o = new Date();break;
case "base64Binary": o = new Number(0);break;
case "int": o = new Number(0);break;
case "long": o = new Number(0);break;
case "integer": o = new Number(0);break;
case "nonPositiveInteger": o = new Number(-1);break;
case "negativeInteger": o = new Number(-1);break;
case "short": o = new Number(0);break;
case "byte": o = new Number(0);break;
case "nonNegativeInteger": o = new Number(0);break;
case "unsignedLong": o = new Number(0);break;
case "unsignedInt": o = new Number(0);break;
case "unsignedShort": o = new Number(0);break;
case "unsignedByte": o = new Number(0);break;
case "positiveInteger": o = new Number(0);break;
default: o = new Object();break;
}
return o;
}
SOAPClient.invoke = function(url, method, parameters, async, callback)
{
if(async)
SOAPClient._loadWsdl(url, method, parameters, async, callback);
else
return SOAPClient._loadWsdl(url, method, parameters, async, callback);
}
// private: wsdl cache
SOAPClient_cacheWsdl = new Array();
// private: invoke async
SOAPClient._loadWsdl = function(url, method, parameters, async, callback)
{
// load from cache?
var wsdl = SOAPClient_cacheWsdl[url];
if(wsdl + "" != "" && wsdl + "" != "undefined")
return SOAPClient._sendSoapRequest(url, method, parameters, async, callback, wsdl);
// get wsdl
var xmlHttp = SOAPClient._getXmlHttp();
xmlHttp.open("GET", ((_wsdl_url + "" != "undefined") ? _wsdl_url : url+ "?wsdl"), async);
if(async)
{
xmlHttp.onreadystatechange = function()
{
if(xmlHttp.readyState == 4)
SOAPClient._onLoadWsdl(url, method, parameters, async, callback, xmlHttp);
}
}
xmlHttp.send(null);
if (!async)
return SOAPClient._onLoadWsdl(url, method, parameters, async, callback, xmlHttp);
}
SOAPClient._onLoadWsdl = function(url, method, parameters, async, callback, req)
{
var wsdl = req.responseXML;
SOAPClient_cacheWsdl[url] = wsdl; // save a copy in cache
return SOAPClient._sendSoapRequest(url, method, parameters, async, callback, wsdl);
}
SOAPClient._sendSoapRequest = function(url, method, parameters, async, callback, wsdl)
{
// get namespace
var ns = (wsdl.documentElement.attributes["targetNamespace"] + "" == "undefined") ? wsdl.documentElement.attributes.getNamedItem("targetNamespace").nodeValue : wsdl.documentElement.attributes["targetNamespace"].value;
// build SOAP request
var sr =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<soap:Envelope " +
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
"xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" " +
"xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
"<soap:Body>" +
"<" + method + " xmlns=\"" + ns + "\">" +
parameters.toXml() +
"</" + method + "></soap:Body></soap:Envelope>";
// send request
var xmlHttp = SOAPClient._getXmlHttp();
xmlHttp.open("POST", url, async);
var soapaction = ((ns.lastIndexOf("/") != ns.length - 1) ? ns + "/" : ns) + method;
xmlHttp.setRequestHeader("SOAPAction", soapaction);
xmlHttp.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
if(async)
{
xmlHttp.onreadystatechange = function()
{
if(xmlHttp.readyState == 4)
SOAPClient._onSendSoapRequest(method, async, callback, wsdl, xmlHttp);
}
}
xmlHttp.send(sr);
if (!async)
return SOAPClient._onSendSoapRequest(method, async, callback, wsdl, xmlHttp);
}
SOAPClient._sendSoapRequest2 = function(url, method, parameters, async, callback, soapClientMethod)
{
// build SOAP request
var ns = soapClientMethod.namespace;
var sr =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<soap:Envelope " +
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
"xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" " +
"xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
"<soap:Body>" +
"<" + method + " xmlns=\"" + ns + "\">" +
parameters.toXml() +
"</" + method + "></soap:Body></soap:Envelope>";
// send request
var xmlHttp = SOAPClient._getXmlHttp();
xmlHttp.open("POST", url, async);
var soapaction = ((ns.lastIndexOf("/") != ns.length - 1) ? ns + "/" : ns) + method;
xmlHttp.setRequestHeader("SOAPAction", soapaction);
xmlHttp.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
if(async)
{
xmlHttp.onreadystatechange = function()
{
if(xmlHttp.readyState == 4)
SOAPClient._processResponse(callback, xmlHttp, soapClientMethod);
}
}
xmlHttp.send(sr);
if (!async)
return SOAPClient._processResponse(null, xmlHttp, soapClientMethod);
}
SOAPClient._processResponse = function(callback, xmlHttp, soapClientMethod)
{
var soapR = xmlHttp.responseXML;
var result = new Array();
var o = {};
var i = 0;
for (p in soapClientMethod.paramsOut)
{
var results = SOAPClient._getElementsByTagName(soapR, p);
var value = null;
if (results.length>0)
{
if (soapClientMethod.paramsOut[p].isAArray)
{
value = new Array();
for (var a = 0; a < results.length; a++)
{
value[a] = SOAPClient._extractValue(results[a].childNodes[0], null, soapClientMethod.paramsOut[p].typeName) ;
}
}
else
{
value = SOAPClient._extractValue(results[0].childNodes[0], null, soapClientMethod.paramsOut[p].typeName) ;
}
} else {
if(req.responseXML.getElementsByTagName("faultcode").length > 0)
throw new Error(500, req.responseXML.getElementsByTagName("faultstring")[0].childNodes[0].nodeValue);
}
var scriptText = "o." + p + "= soapClientMethod.paramsOut[p]; result[" + i
+ "] = soapClientMethod.paramsOut[p]; result[" + i + "] = value; o." + p + " = value;";
(global.eval) ? global.eval(scriptText) : eval(scriptText);
i++;
}
if (callback != null) {
var scriptText = "callback(";
for (var rs = 0; rs < result.length; rs++ )
{
scriptText += "result[ " + rs + " ], ";
}
scriptText = scriptText.substring(0, scriptText.lastIndexOf(','));
scriptText += ");";
if (result.length>0)
(global.eval) ? global.eval(scriptText) : eval(scriptText);
}
if (result.length == 1) return result[0];
return o;
}
SOAPClient._onSendSoapRequest = function(method, async, callback, wsdl, req)
{
var o = null;
var nd = SOAPClient._getElementsByTagName(req.responseXML, method + "Result");
//if nothing is found, lets try method + Response...
if(nd.length == 0) nd = SOAPClient._getElementsByTagName(req.responseXML, method + "Response");
if(nd.length == 0) {
//still nothing, we've got a wsdl let's try to find it.
//caching should be added later
var nodes = req.responseXML.getElementsByTagName("ouput");
for (var h=0; h<nodes.length() && nd.length == 0;h++) {
var output = nodes[h];
if (output.nodeName="output" && (output.getAttribute("message") + "") != "undefined" ) {
var responseNS = output.getAttribute("message");
var response = responseNS.split(':')[responseNS.split(':').length - 1];
nd = SOAPClient._getElementsByTagName(req.responseXML, response);
}
}
}
if(nd.length == 0)
{
if(req.responseXML.getElementsByTagName("faultcode").length > 0)
{
if(async || callback)
o = new Error(500, req.responseXML.getElementsByTagName("faultstring")[0].childNodes[0].nodeValue);
else
throw new Error(500, req.responseXML.getElementsByTagName("faultstring")[0].childNodes[0].nodeValue);
}
}
else
o = SOAPClient._soapresult2object(nd[0], wsdl);
if(callback)
callback(o, req.responseXML);
if(!async)
return o;
}
// private: utils
SOAPClient._getElementsByTagName = function(document, tagName)
{
try
{
// trying to get node omitting any namespaces (latest versions of MSXML.XMLDocument)
var tmp = document.selectNodes(".//*[local-name()=\""+ tagName +"\"]");
if (tmp != null && tmp.length >0) return tmp;
}
catch (ex) {}
// old XML parser support
var aResult = document.getElementsByTagName(tagName);
// namespace and old DOM and ie
if (aResult.length >0) return aResult;
var i=0, oTemp;
for(i; i < document.childNodes.length; i++)
{
oTemp=document.childNodes[i];
if(oTemp.localName==tagName) aResults.push(oTemp);
}
return aResult;
}
SOAPClient._soapresult2object = function(node, wsdl)
{
return SOAPClient._node2object(node, wsdl);
}
SOAPClient._node2object = function(node, wsdl)
{
// null node
if(node == null)
return null;
// text node
if(node.nodeType == 3 || node.nodeType == 4)
return SOAPClient._extractValue(node, wsdl);
// leaf node
if (node.childNodes.length == 1 && (node.childNodes[0].nodeType == 3 || node.childNodes[0].nodeType == 4))
return SOAPClient._node2object(node.childNodes[0], wsdl);
var isarray = SOAPClient._getTypeFromWsdl(node.nodeName, wsdl).toLowerCase().indexOf("arrayof") != -1;
// object node
if(!isarray)
{
var obj = null;
if(node.hasChildNodes())
obj = new Object();
for(var i = 0; i < node.childNodes.length; i++)
{
var p = SOAPClient._node2object(node.childNodes[i], wsdl);
obj[node.childNodes[i].nodeName] = p;
}
return obj;
}
// list node
else
{
// create node ref
var l = new Array();
for(var i = 0; i < node.childNodes.length; i++)
l[l.length] = SOAPClient._node2object(node.childNodes[i], wsdl);
return l;
}
return null;
}
SOAPClient._extractValue = function(node, wsdl, type)
{
var value = node.nodeValue;
if (type == null)
type = SOAPClient._getTypeFromWsdl(node.parentNode.nodeName, wsdl).toLowerCase();
else type = "s:" + type;
switch(type)
{
default:
case "s:string":
return (value != null) ? value + "" : "";
case "s:boolean":
return value+"" == "true";
case "s:int":
case "s:long":
return (value != null) ? parseInt(value + "", 10) : 0;
case "s:double":
return (value != null) ? parseFloat(value + "") : 0;
case "s:datetime":
if(value == null)
return null;
else
{
value = value + "";
value = value.substring(0, value.lastIndexOf("."));
value = value.replace(/T/gi," ");
value = value.replace(/-/gi,"/");
var d = new Date();
d.setTime(Date.parse(value));
return d;
}
}
}
SOAPClient._getTypeFromWsdl = function(elementname, wsdl)
{
var ell = wsdl.getElementsByTagName("s:element"); // IE
if(ell.length == 0)
ell = wsdl.getElementsByTagName("element"); // MOZ
for(var i = 0; i < ell.length; i++)
{
if(ell[i].attributes["name"] + "" == "undefined") // IE
{
if(ell[i].attributes.getNamedItem("name") != null && ell[i].attributes.getNamedItem("name").nodeValue == elementname && ell[i].attributes.getNamedItem("type") != null)
return ell[i].attributes.getNamedItem("type").nodeValue;
}
else // MOZ
{
if(ell[i].attributes["name"] != null && ell[i].attributes["name"].value == elementname && ell[i].attributes["type"] != null)
return ell[i].attributes["type"].value;
}
}
return "";
}
// private: xmlhttp factory
SOAPClient._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;
}
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");
}
-- modified at 8:24 Friday 11th August, 2006
|
|
|
|
|
Can you provide a server side example of usage?
Thanks
dadgad
|
|
|
|
|
You've made a typo in the SOAPClient._loadWsdl method - you've put wdsl instead of wsdl.
// private: invoke async
SOAPClient._loadWsdl = function(url, method, parameters, async, callback)
{
// load from cache?
var wsdl = SOAPClient_cacheWsdl[url];
if(wsdl + "" != "" && wsdl + "" != "undefined")
return SOAPClient._sendSoapRequest(url, method, parameters, async, callback, wsdl);
// get wsdl
var xmlHttp = SOAPClient._getXmlHttp();
xmlHttp.open("GET", ((_wdsl_url + "" != "undefined") ? _wdsl_url : url+ "?wdsl"), async); <--- Error here.
I'd post the correct code, but I've changed all the instances of the mis-spelled word, even in the variables.
|
|
|
|
|
Thanks manzanotti,
I´ve changed the code as you suggested.
Regards, Marco.
|
|
|
|
|
with your modification to the soapclient, if i have the wsdl in my own client domain..how do i modify modify your source? or maybe the question is is it possible to add a method to pass the wsdl file?
|
|
|
|
|
I am calling a remote webservice that returns a DataSet
When I use the code you supplied in my Atlas application, it throws an exception as this type (function) is not , so I tried to add case for the DataSet but I just cant figureout how to handle it
case "function":
alert(o.toString());
'
'
'
'
case "function":
type = "DataSet"; break;
It then alerted some functions but I really dont know how to use them, Any way to handle DataSet??
|
|
|
|
|
Hello mashry68,
Can you send/post a WSDL example or link?
Regards, Marco.
|
|
|
|
|
I had this question too....
My application like this:
var url = "http://localhost/DiningRoom/webservices/ws_Products_Sort.asmx";
var pl = new SOAPClientParameters();
//pl.add("Name","Jack");
SOAPClient.invoke(url,"getProductSort",pl,true,ProductSortBack);
function ProductSortBack(val)
{
//the result is type of DataSet How can i use them .....
//help me pls ..thanks very much
}
[WebMethod]
public DataSet getProductSort()
{
string ColumenList = "IID,OID,ID,CName";
string tbName = "Product_Sort";
string Condition = "";
string OrderBy = "IID,OID ASC";
return db.getDataSet(ColumenList,tbName,Condition,OrderBy,"");
}
|
|
|
|
|
soapclient.js does not work when used in the same page as the latest version of prototype.js, see http://prototype.conio.net/
That is very unfortunate! I'll be back later to see what must be done to resolve this...
-- modified at 15:47 Thursday 22nd June, 2006
|
|
|
|
|
OK, to fix this open soapclient.js and go to line 93-94 and replace with:
<br />
default:<br />
-- modified at 17:47 Thursday 22nd June, 2006
And go to line 18 and change to:
<br />
this.toXml = function()<br />
{<br />
var xml = "";<br />
for(var p in _pl) {<br />
switch(typeof(_pl[p])) {<br />
case "string":<br />
case "number":<br />
case "boolean":<br />
case "object": <br />
xml += "<" + p + ">" + SOAPClientParameters._serialize(_pl[p]) + "</" + p + ">";<br />
break;<br />
default:<br />
break;<br />
}<br />
}<br />
return xml; <br />
}<br />
Only _serialize() if a serializable type!!
|
|
|
|
|
small correction to the previous post: for the second block (line 18),
use this:
-----------------------------------
this.toXml = function()
{
var xml = "";
for(var p in _pl) {
switch(typeof(_pl[p])) {
case "string":
case "number":
case "boolean":
case "object":
xml += "<" + p + ">" + SOAPClientParameters._serialize(_pl[p]) + "</" + p + ">";
break;
default:
break;
}
}
return xml;
}
----------------------------------
(that is, the xml node has to be closed!)
this refers to the soapclient version 2.1
http://www.guru4.net/articoli/javascript-soap-client/en/
Thanks for the great work!
|
|
|
|
|
According to http://www-128.ibm.com/developerworks/webservices/library/ws-whichwsdl/ there are several styles of WSDL: rpc/encoded, rpc/literal, document/literal and document/literal wrapped.
Only the ones with literal are WS-I compliant so reachable from mobile devices for example.
My question is does soapclient.js handle all types of WSDL equally well? If not which are the preferred ones.
Super library by the way!
|
|
|
|
|
Hi,
I've been trying to use your client with a soap service generated by nusoap, but haven't been able to do so. Call the SOAP service with php works fine, but when I call the service with JavaScript I get a null value. The service is on a local domain.
The code appears to make the rpc call properly, but I think it's having trouble extracting the return value.
Has anyone done this successfully? Any ideas what to look for?
thanks for any thoughts,
-- Nabeel
|
|
|
|
|
Well if you look at the item listed under BUG, you'lll also find the solution:
nusoap sends replys that use methodnameResponse as an envelope tag. So the parser cannot succeed when it looks for methodnameReturn of methodnameResult. As all three appear to be used, maybe the excellent soapclient.js shoudl check for all three!
for you:
in SOAPClient._onSendSoapRequest() change:
var nd = SOAPClient._getElementsByTagName(req.responseXML, method + "Result");
to read:
var nd = SOAPClient._getElementsByTagName(req.responseXML, method + "Response");
I'm using soapclient.js for testing at my website on lighting calculations:
http://www.fold1.com/fcapplet.php#soapjs and it performs excellently!
Mateo, Thanks!
maarten
|
|
|
|
|
Thanks, Maarten. I didn't realize that what was happening under the thread BUG applied here. I'll give this a try.
-- Nabeel
|
|
|
|
|
Hi,
Isn't possible cross-domain calls in any way ?
Your JavaScript SOAP Client is great but without it I can't use...
Any idea are welcome !
Thanks,
Alexnaldo Santos
|
|
|
|
|
Hi Alexnaldo,
There are 3 ways to make AJAX cross-domain enabled:
1) using some hacking, such as iframe or flash. IMHO this is not the better way!
2) using a proxy or a web service wrapper (on the server side solution)
3) using JSON and Dynamic script tag
As Dan Theurer (http://www.theurer.cc/blog/2005/12/15/web-services-json-dump-your-proxy/[^]) says:
Proxy method
-------------
- More robust, error handling is easier
- More control on the server side
- It has some security implications on the server side as the proxy could be abused.
- The server side can have additional functionality implemented that is hidden to the caller e.g. login, exchange secrets...
Dynamic script tag
-------------------
- No XML parsing necessary
- Performance win
- No traffic gets routed (and counted) on your end.
- JSON converters don’t know that they should define an array if they is only one nested element in a tag, even if the Schema allows 1..n
- More cross-browser issues
- Positive impact on rate limiting if it’s done per IP
- No need to set up a proxy
But with dynamic script tag you need to add a JSON response method to your web services...
Matteo Casati
www.guru4.net
|
|
|
|
|
Hi Matteo,
I was working with SOAP implementation in Java and "reused" your AJAX SOAP JavaScript client which is excellent, by the way.
However, in SOAPClient._onSendSoapRequest method where it says:
var nd = SOAPClient._getElementsByTagName(
req.responseXML, method + "Result");
Should not it be:
var nd = SOAPClient._getElementsByTagName(
req.responseXML, method + "Return");
Alternatively, I could always switch back to using JSON
Regards,
Eki Y. Baskoro
|
|
|
|
|
Hello!
Very nice Helper! Thanks!
I coundn't run in a "desconected" .htm file. I create a simple .htm file and added a external web service reference and I received a "Error in page - Access Denied".
How I do to run in a stand alone html file?
Very thanks!
|
|
|
|
|
As you can read in the article: "please note that many browsers do not allow cross-domain calls for security reasons", so you can't use the SOAP Client (or other AJAX library) in "disconnected" mode.
Sorry.
Matteo Casati
www.guru4.net
|
|
|
|
|
I had a problem with running the client to call an apache/axis webservice.
The service serialized the returning java vector as a "apachesoap:vector" type in the wsdl file; so the client was not able to deserialize the xml to a javascript object!
For solution i modified the soapclient.js SOAPClient._node2object function to use exernal, user - extendable deserializer functions for inner tree nodes and use the two for array and object as default Deserializer.
Now i am able to use the client with any webservice with any types because users are able to register their own deserialization functions.
Further i had to modify the SOAPClient._onSendSoapRequest function because not every server uses a "<functionname>Result" tag which is used hardcoded in the client to return the service data; for example apache/axis uses an "<functionname>Return" tag. So i enter the dom tree at the top level element: "<functionname>Response" which is available in all soap implementations.
If you are interested in the code just contact me.
At last: this client was really good work!
Reinhard Holzmann
|
|
|
|
|
|
First, this is very nice work!
I tried to work with long lists of objects and noticed that the object creation from the soap response gets rather slow for long lists of objects. Maybe you could remove the browser detection stuff from inside the loops and recursion to speed things up
-hb
|
|
|
|
|
I hope to find a solution for this problem in next weeks.
Thanks.
Matteo Casati
www.guru4.net
|
|
|
|
|