Question

I have a problem with the below javascript file.
It's supplied by a third party, and worked only in IE QuirksMode.
Because I don't control the server backend, I can't change the API to JSON instead of SOAP, and avoid the completely braindead script altogether.

So I fixed the script so it also works in IE standards mode in IE 10/11 in a non-intranet environment.
While I was at it, I tried to fix it for Chrome, too.

I have only one remaining problem that I can't solve:

In function GetSOAPResponseEx i get the following error:

Uncaught NamespaceError: Failed to execute 'evaluate' on 'Document': The string '//ns1:RunLocatorResponse' contains unresolvable namespaces. SOAPAPI.js:64
XMLDocument.selectSingleNode SOAPAPI.js:64
GetSOAPResponseEx SOAPAPI.js:371
loadOrgRoleUserNames AWEMain.aspx:156

but I don't know why or how to fix it.

My hunch is that

objXmlDoc.setProperty("SelectionNamespaces", 'xmlns:ns1="http://tempuri.org/AWEService/API/WASAPI"');

does not exactly the same thing as

  objXmlDoc = objXmlDomParser.parseFromString(szResponse, "text/xml");
            objXmlDoc.documentElement.setAttribute("xmlns:ns1", "http://tempuri.org/AWEService/API/WASAPI");

But I don't know if the problem is setAttribute or something in selectSingleNode.

This are the XML files the selectSingleNode xpath query runs on:

-- Chrome

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope 
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:ns1="http://tempuri.org/AWEService/API/WASAPI">

<soapenv:Body>

<ns1:RunLocatorResponse xmlns="urn:RunLocator" 
xmlns:ns1="http://tempuri.org/AWEService/API/WASAPI" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

<ns1:RunLocatorResult>
<ns1:Target>Administrator</ns1:Target>
<ns1:FirstName>Administrator</ns1:FirstName>
<ns1:LastName>Administrator</ns1:LastName>
</ns1:RunLocatorResult>
<ns1:RunLocatorResult>

<ns1:Target>MyFirstName.MyLastName</ns1:Target>
<ns1:FirstName>MyFirstName</ns1:FirstName>
<ns1:LastName>MyLastName</ns1:LastName>
</ns1:RunLocatorResult>
</ns1:RunLocatorResponse>

</soapenv:Body>
</soapenv:Envelope> 

And this XML is from IE

 -- IE 

<?xml version="1.0"?>
<soapenv:Envelope 
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

    <soapenv:Body>

        <ns1:RunLocatorResponse xmlns="urn:RunLocator" 
        xmlns:ns1="http://tempuri.org/AWEService/API/WASAPI" 
        xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

            <ns1:RunLocatorResult>
                <ns1:Target>Administrator</ns1:Target>
                <ns1:FirstName>Administrator</ns1:FirstName>
                <ns1:LastName>Administrator</ns1:LastName>
            </ns1:RunLocatorResult>
            <ns1:RunLocatorResult>
                <ns1:Target>MyFirstName.MyLastName</ns1:Target>
                <ns1:FirstName>MyFirstName</ns1:FirstName>
                <ns1:LastName>MyLastName</ns1:LastName>
            </ns1:RunLocatorResult>
        </ns1:RunLocatorResponse>
    </soapenv:Body>
</soapenv:Envelope>

And this is the file in question:

/*  File:   SOAPAPI.js
Functions that encapsulate a portal SOAP functions
*/
//-------------------------------------------------------------------------
// Global variables specifically for device placement
//-------------------------------------------------------------------------

// Variables used to communicate with the server via SOAP
var objXmlDoc;
var objXmlDomParser;
var objHttp;
var bDocument = false;
var bHttp = false;
var ghttpAsync = true;

/*
// http://richardpianka.com/2011/01/cross-browser-xpath/
if (document.implementation.hasFeature("XPath", "3.0")) {
if (typeof XMLDocument == "undefined") { XMLDocument = Document; }

XMLDocument.prototype.selectNodes = function(cXPathString, xNode) {
if (!xNode) { xNode = this; }
var oNSResolver = this.createNSResolver(this.documentElement)
var aItems = this.evaluate(cXPathString, xNode, oNSResolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null)
var aResult = [];
for (var i = 0; i < aItems.snapshotLength; i++) { aResult[i] = aItems.snapshotItem(i); }
return aResult;
}

XMLDocument.prototype.selectSingleNode = function(cXPathString, xNode) {
if (!xNode) { xNode = this; }
var xItems = this.selectNodes(cXPathString, xNode);
if (xItems.length > 0) { return xItems[0]; }
else { return null; }
}

Element.prototype.selectNodes = function(cXPathString) {
if (this.ownerDocument.selectNodes) { return this.ownerDocument.selectNodes(cXPathString, this); }
else { throw "For XML Elements Only"; }
}

Element.prototype.selectSingleNode = function(cXPathString) {
if (this.ownerDocument.selectSingleNode) { return this.ownerDocument.selectSingleNode(cXPathString, this); }
else { throw "For XML Elements Only"; }
}


}

*/


var isIE = /**@preserve/*@cc_on!@*/false;

if (!isIE) {

    // http://doogalbellend.blogspot.ch/2012/04/cross-browser-selectsinglenode-for-xml.html
    //function SelectSingleNode(xmlDoc,
    XMLDocument.prototype.selectSingleNode = function(elementPath) 
    {
        var xmlDoc = this;
        if (xmlDoc.evaluate) 
        {
            var nodes = xmlDoc.evaluate(elementPath, xmlDoc, null, XPathResult.ANY_TYPE, null);
            var results = nodes.iterateNext();
            return results;
        }
        else
            return xmlDoc.selectSingleNode(elementPath);
    }

} // End if (!isIE) {




//-------------------------------------------------------------------------
// Create a generally used DOM document object used to process the result sets
//-------------------------------------------------------------------------
function CreateDOMDocument() {
    if (bDocument != false)
        return bDocument;

    if (window.DOMParser) {
        objXmlDomParser = new DOMParser();
        bDocument = true;
        // objXmlDoc = objXmlDoc.parseFromString(txt, "text/xml");
    }
    else // Internet Explorer
    {
        objXmlDoc = new ActiveXObject("Microsoft.XMLDOM");
        objXmlDoc.async = false;
        bDocument = true;
    }

    return bDocument;
}



function CreateDOMDocument_old() {
    if (bDocument == false) {
        // Create the XML Document object

        var aszDocumentProgIDs = ["MSXML2.DOMDocument.4.0",
                               "MSXML2.DOMDocument.3.0",
                               "MSXML2.DOMDocument",
                               "MSXML.DOMDocument",
                               "Microsoft.XmlDom"];

        for (var i = 0; !bDocument && i < aszDocumentProgIDs.length; i++) {
            try {
                objXmlDoc = new ActiveXObject(aszDocumentProgIDs[i]);
                bDocument = true;
            } catch (objException) {
                // error handling elided for clarity
            }
        }
    }
    return bDocument;
}








function CreateHTTPSocket() {
    // http://stackoverflow.com/questions/2557247/easiest-way-to-retrieve-cross-browser-xmlhttprequest
    if (bHttp != false)
        return bHttp;

    var XMLHttpFactories = [
        function() { return new XMLHttpRequest() },
        function() { return new ActiveXObject("Msxml3.XMLHTTP") },
        function() { return new ActiveXObject("Msxml2.XMLHTTP.4.0") },
        function() { return new ActiveXObject("Msxml2.XMLHTTP.3.0") },
        function() { return new ActiveXObject("Msxml2.XMLHTTP") },
        function() { return new ActiveXObject("Microsoft.XMLHTTP") }
    ];


    for (var i = 0; i < XMLHttpFactories.length; i++) {
        try {
            objHttp = XMLHttpFactories[i]();
            bHttp = true;
        }
        catch (e) {
            continue;
        }
        break;
    }

    return bHttp;
}



//-------------------------------------------------------------------------
// Create a generally used HTTP socket object used to communicate with WAS
//-------------------------------------------------------------------------
function CreateHTTPSocket_old() {
    if (bHttp == false) {
        // Create the XML HTTP object

        var aszHttpProgIDs = ["MSXML2.XMLHTTP.4.0",
                           "MSXML2.XMLHTTP.3.0",
                           "MSXML2.XMLHTTP",
                           "Microsoft.XMLHTTP"];

        var aszHttpAsyncFlags = [true,
                  true,
                  false,
                  false];

        for (var i = 2; !bHttp && i < aszHttpProgIDs.length; i++) {
            try {
                objHttp = new ActiveXObject(aszHttpProgIDs[i]);
                bHttp = true;
                ghttpAsync = aszHttpAsyncFlags[i];
            } catch (objException) {
                // error handling elided for clarity
            }
        }
    }

    return bHttp;
}

//-------------------------------------------------------------------------
// Insert the specified search parameters into a SOAP parameter block.  The
// block types currently supported are for locate, create, change, or delete  
// functions
//-------------------------------------------------------------------------
function SOAPEnvelopeEx(action, formIDParms, formFieldsParms, allowNulls) {
    var strEnvelope;
    var actionVerb;
    var parms;
    var allowNullsParm = '';

    if ((typeof allowNulls == 'boolean') && (allowNulls == true)) allowNullsParm = ' AllowNulls="yes"';

    switch (action) {
        case 'Locate':
            actionVerb = 'RunLocator';
            parms = "<locatorSearchFieldsIdentification>" +
        formIDParms +
           "</locatorSearchFieldsIdentification>";
            break;
        case 'CreateNewInstance':
            actionVerb = 'CreateNewInstance';
            parms = "<formIdenfication>" +
        formIDParms +
            "</formIdenfication>" +
        "<formFieldsIdentification>" +
        formFieldsParms +
        "</formFieldsIdentification>";
            break;
        case 'ChangeInstance':
            actionVerb = 'ChangeInstance';
            parms = "<formFieldsIdentification>" +
        formIDParms +
        "</formFieldsIdentification>";
            break;
        case 'DeleteInstance':
            actionVerb = 'DeleteInstance';
            parms = "<formFieldsIdentification>" +
        formIDParms +
        "</formFieldsIdentification>";
            break;
        case 'SetInstanceProperty':
            actionVerb = 'SetInstanceProperty';
            parms = "<formIDIdentification>" +
          formIDParms +
        "</formIDIdentification>" +
        "<instancePropertyIdentification>" +
          formFieldsParms +
        "</instancePropertyIdentification>";
            break;
        default:
            alert("Unrecognized parameter in formSoapEnvelope");
    }

    strEnvelope = "<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><" + actionVerb + " xmlns='http://tempuri.org/AWEService/API/WASAPI'" + allowNullsParm + ">" +
        "<userIdentification><WAS_userName>" + g_SOAPUSERID + "</WAS_userName>" +
                       "<WAS_session>" + g_SOAPTransID + "</WAS_session>" +
        "</userIdentification>" +
        parms +
        "</" + actionVerb + "></soap:Body> </soap:Envelope>";

    return strEnvelope;
}


//-------------------------------------------------------------------------
// Use an HTTP socket to pass the SOAP information to WAS.  Identify the 
// routine that will be driven when the result arrives.  Supports locate,
// create, change, or delete functions.
//-------------------------------------------------------------------------
function CallSOAPEx(action, handler, formName, strEnvelope) {
    // Must be using IE for this to work
    // if (!window.ActiveXObject) return;
    if (!CreateDOMDocument()) return;
    if (!CreateHTTPSocket()) return;

    var functionURL = RemoveSSFromURLPrefix(g_SOAPURL) + "/API/AWEService.asmx?w_v=1&w_s=" + g_SUITE_ID;

    var actionVerb;
    var parms;
    switch (action) {
        case 'Locate':
            actionVerb = 'RunLocator';
            parms = functionURL + "&w_o=" + formName;
            break;
        case 'CreateNewInstance':
            actionVerb = 'CreateNewInstance';
            parms = functionURL + "&w_ifn=" + formName;
            break;
        case 'ChangeInstance':
            actionVerb = 'ChangeInstance';
            parms = functionURL + "&w_o=" + formName;
            break;
        case 'DeleteInstance':
            actionVerb = 'DeleteInstance';
            parms = functionURL + "&w_o=" + formName;
            break;
        case 'SetInstanceProperty':
            actionVerb = 'SetInstanceProperty';
            parms = functionURL + "&w_o=" + formName;
            break;
        default:
            alert("Unrecognized parameter in formCallSoap");
    }

    // Set up the post
    objHttp.onreadystatechange = handler;
    objHttp.open("post", parms, ghttpAsync);

    // http://blogs.msdn.com/b/ie/archive/2012/07/19/xmlhttprequest-responsexml-in-ie10-release-preview.aspx
    // !! Important !! 
    try { objHttp.responseType = 'msxml-document'; } catch (e) { }

    objHttp.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
    objHttp.setRequestHeader("SOAPAction", "http://tempuri.org/AWEService/API/WASAPI/" + actionVerb);
    objHttp.send(strEnvelope);
    if (!ghttpAsync)
        handler();
}

function RemoveSSFromURLPrefix(urlPrefix) {
    if (urlPrefix != null) {
        var i = urlPrefix.toUpperCase().lastIndexOf("/SS");
        if (i > 1) {
            return urlPrefix.substring(0, i);
        }
    }
    return urlPrefix;
}

//-------------------------------------------------------------------------
// Find the multi-instance form Response within the response XML
//-------------------------------------------------------------------------
// also see: https://www9.cor-asp.ch/Wincasa_Portal/menu_com.js
function GetSOAPResponseEx(action) {
    if (objHttp.readyState != 4) return null;

    // Get the return envelope
    var szResponse = objHttp.responseText;
    // console.log(szResponse);

    if (window.DOMParser) {
        // console.log(objXmlDoc);
        objXmlDoc = objHttp.responseXML; // Because responseType = 'msxml-document'

        try {
            objXmlDoc.setProperty("SelectionNamespaces", 'xmlns:ns1="http://tempuri.org/AWEService/API/WASAPI"');
            // console.log(objXmlDoc.xml);
        }
        catch (e) {
            // console.log("DomParserException");
            // console.log(typeof (objXmlDoc));
            // console.log(objXmlDoc.selectSingleNode);
            objXmlDoc = objXmlDomParser.parseFromString(szResponse, "text/xml");
            objXmlDoc.documentElement.setAttribute("xmlns:ns1", "http://tempuri.org/AWEService/API/WASAPI");

            // console.log((new XMLSerializer()).serializeToString(objXmlDoc));
            // $(xmlDOM.documentElement).attr("xmlns:xsd", "http://www.w3.org/2001/XMLSchema");
        }

    }
    else 
    {
        objXmlDoc.loadXML(szResponse);
        objXmlDoc.setProperty("SelectionNamespaces", 'xmlns:ns1="http://tempuri.org/AWEService/API/WASAPI"');
    }

    // At this point, the 2 xml's have been logged

    /*
    console.log("foo");

    // Here I get: 
    // Uncaught NamespaceError: Failed to execute 'evaluate' on 'Document': 
    // The string '//ns1:RunLocatorResponse' contains unresolvable namespaces.         SOAPAPI.js:64

XMLDocument.selectSingleNode

    objXmlDoc.selectSingleNode('//ns1:RunLocatorResponse');
    console.log("bar");
    */

    switch (action) {
        case 'Locate':
            return objXmlDoc.selectSingleNode('//ns1:RunLocatorResponse');
        case 'CreateNewInstance':
            return objXmlDoc.selectSingleNode('//ns1:CreateNewInstanceResponse');
        case 'ChangeInstance':
            return objXmlDoc.selectSingleNode('//ns1:ChangeInstanceResponse');
        case 'DeleteInstance':
            return objXmlDoc.selectSingleNode('//ns1:DeleteInstanceResponse');
        case 'SetInstanceProperty':
            return objXmlDoc.selectSingleNode('//ns1:SetInstancePropertyResponse');
        default:
            alert("Unrecognized parameter in GetSOAPResponseEx");
    }

}
Was it helpful?

Solution

As the error message Failed to execute 'evaluate' on 'Document' indicates, the problem occurs with the evaluate method of the DOM document object you or your library uses to select nodes using XPath. To use a path expression with a prefix like //ns1:RunLocatorResponse you need to make sure the evaluate methods knows how to resolve that prefix by doing e.g.

xmldoc.evaluate(
    '//ns1:RunLocatorResponse',
    xmldoc,
    function (prefix) {
        if (prefix === 'ns1')
            return 'http://tempuri.org/AWEService/API/WASAPI';
        else
            return null;
    },
    XPathResult.ANY_TYPE,
    null
);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top