JavaScript:字符串 '//ns1:RunLocatorResponse' 在 Chrome 中包含无法解析的命名空间 - 为什么?

标签 javascript internet-explorer soap xpath xmlhttprequest

我对以下 javascript 文件有疑问。
它由第三方提供,并且只能在 IE QuirksMode 下运行。
因为我不控制服务器后端,所以我无法将 API 更改为 JSON 而不是 SOAP,并完全避免完全脑残的脚本。

所以我修复了脚本,因此它也可以在非 Intranet 环境中的 IE 10/11 的 IE 标准模式下工作。
当我在做的时候,我也尝试为 Chrome 修复它。

我只剩下一个问题无法解决:

在函数 GetSOAPResponseEx 中我得到以下错误:

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

但我不知道为什么或如何解决它。

我的预感是

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

不完全一样

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

但是不知道是setAttribute的问题还是selectSingleNode的问题

这是运行 selectSingleNode xpath 查询的 XML 文件:

-- 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> 

这个XML来自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>

这是有问题的文件:

/*  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");
    }

}

最佳答案

如错误消息 Failed to execute 'evaluate' on 'Document' 所示,问题发生在您或您的库使用的 DOM 文档对象的 evaluate 方法上使用 XPath 选择节点。要使用带有 //ns1:RunLocatorResponse 前缀的路径表达式,您需要确保 evaluate 方法知道如何通过执行以下操作来解析该前缀

xmldoc.evaluate(
    '//ns1:RunLocatorResponse',
    xmldoc,
    function (prefix) {
        if (prefix === 'ns1')
            return 'http://tempuri.org/AWEService/API/WASAPI';
        else
            return null;
    },
    XPathResult.ANY_TYPE,
    null
);

关于JavaScript:字符串 '//ns1:RunLocatorResponse' 在 Chrome 中包含无法解析的命名空间 - 为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23110310/

相关文章:

javascript - ie 11 的对象适配替代方案

JavaScript 与 ajax 在 FF 中有效,但在 IE 中无效

ios - 在 Swift iPhone 应用程序中请求 SOAP Web 服务时 XMLStreamreader 错误

javascript - John Resigs 微型模板引擎,如何处理选择的问题?

javascript - 请解释一下这个递归javascript函数

javascript - 如何在 Jquery selectize 中找到 EOL(行尾)?

.net - IEndpointBehavior ApplyClientBehavior 方法在行为添加到端点行为后未执行

javascript - json值的长度?

html - IE Z-INDEX 问题

go - 如何使用 gowsdl 连接 soap 服务器?